Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Bin ich schon zerstört? (https://www.delphipraxis.net/56601-bin-ich-schon-zerstoert.html)

phXql 8. Nov 2005 18:24

Re: Bin ich schon zerstört?
 
Zitat:

Zitat von SirThornberry
man kann aber auch einfach auf eine "nil" instanz eine methode anwenden. Solange in der Methode (wie schon geschrieben wurde) nicht auf membervariablen zugegriffen wird kommt es da auch nicht zum Fehler.
Delphi-Quellcode:
TKlasse(nil).Methode;
In diesem fall ist dann nur "Self" innerhalb der Methode nil

ja, aber damit gaukelst du doch dem compiler vor, eine instanz zu haben.

Du kannst ja nicht TKlasse.Free aufrufen, wenn Free() keine static-methode ist...

alzaimar 8. Nov 2005 18:37

Re: Bin ich schon zerstört?
 
Zitat:

Zitat von Khabarakh
Genau. Es wäre ja wirklich sinnlos, wenn in Free Self auf nil geprüft wird, aber schon beim Methodenaufruf wegen Self = nil eine Exception ausgelöst würde.

Free ist aber genauso definiert:
Delphi-Quellcode:
Procedure TObject.Free;
Begin
  If Self<>Nil Then Destroy;
End;
Das dient genau dazu, Nil-Referenzen auf Klassen 'aus Versehen' nochmals freizugeben, ohne das einem das Programm um die Ohren ballert.
Du kannst ohne Probleme TFooObject(4711).SomeMethod ausführen. Das klappt sogar, solange keine Felder der Klasse verwendet werden. Aber ich wiederhole ja nur das, was hier Andere schon geschrieben haben.

Zurück zum Thema:

Wenn Du mehrere Referenzen auf ein Objekt hast, dann benötigst Du Referenzzähler. COM-Objekte implementieren das, und Delphi unterstützt COM-Objekte. Schau mal in der Hilfe nach, wie mal COM-Objekte deklariert und verwendet, eigentlich ganz einfach.

Prinzipiell geht das so: Bei jeder Referenz auf das Objekt erhöhst Du den Referenzzähler. Anstatt das Objekt freizugeben, rufst Du eine Methode 'Release' auf, in der Du den Zähler wieder erniedrigst. Wenn der Zähler 0 ist, gibst Du das Objekt wieder frei.
Delphi-Quellcode:
Function GetReferenceToMyObject : TMyObject;
Begin
  If not Assigned (PrivateObject) Then
    PrivateObject.Create;
  PrivateObject.IncreaseRefCount;
End;

Procedure TPrivateObject.Release;
Begin
  DecreaseRefCount;
  If fRefCount = 0 Then Free;
End;
Aufpassen beim Anfassen der Refcounts: Am Besten sollte man das noch threadsicher kapseln (Oder, wie gesagt, COMs nehmen).

Khabarakh 8. Nov 2005 19:44

Re: Bin ich schon zerstört?
 
Zitat:

Zitat von alzaimar
Zitat:

Zitat von Khabarakh
Genau. Es wäre ja wirklich sinnlos, wenn in Free Self auf nil geprüft wird, aber schon beim Methodenaufruf wegen Self = nil eine Exception ausgelöst würde.

Free ist aber genauso definiert:
Delphi-Quellcode:
Procedure TObject.Free;
Begin
  If Self<>Nil Then Destroy;
End;

Das ist mir bewusst, die Modi waren nicht unabsichtlich so gewählt :wink: . Es ging ja darum, dass man Methoden auch ohne Instanz aufrufen kann (wäre dies nicht so, würde eben obige if-Verzweigung keinen Sinn, da nie erfüllt, machen).

Sidorion 9. Nov 2005 08:27

Re: Bin ich schon zerstört?
 
Das mit den Referenzzählern geht nicht, weil
a) viel zu viel Aufwand (wird nicht bezahlt) und
b) das schon seine Richtigkeit hat, das das Objekt schon zerstört ist, weil wenn nicht, gäbs an anderer Stelle Probleme.

Der_Unwissende 9. Nov 2005 08:45

Re: Bin ich schon zerstört?
 
Hey,
ich glaube es gibt keinen guten Weg das ohne try ... except ... abzufangen. Aber als Alternative, gibst du die Instanzen selbst frei? Dann solltest du einfach dafür sorgen, dass FreeAndNil aufgerufen wird (oder selbst danach den Variablenzeiger nil setzen). Ok, ich glaube ehrlich gesagt, dass wenn es so einfach wäre du selbst drauf gekommen wärst, aber kann ja sein.
Ansonsten scheinen die anderen Möglichkeiten nicht wirklich zu funktionieren (zumal Referenzzähler ja nicht anzeigen können ob eine Instanz existiert oder nicht).

Gruß Der Unwissende

shmia 9. Nov 2005 09:21

Re: Bin ich schon zerstört?
 
Zitat:

Zitat von Sidorion
Die Instanz wird ganz normal zerstürt, habe aber zwei Zeiger drauf und die wissen voneinander nix.

Das ist für mich der entscheidende Satz.
alzaimar hat dir ja schon vorgeschlagen, Inferfaces und Referenzzählung einzusetzen.

Du erzeugst ein Objekt und speicherst es in mehr als einer (Objekt-)Variablen.
Wenn nun gleichzeitig die Gefahr besteht, dass das Objekt freigeben werden kann aber
die Objekt-Variablen weiterhin leben (also im Scope bleiben), hast du einen Software Designfehler
begangen.
Jeder Versuch, den Fehler mit Try..Except auszubügeln ist Banane.
Entweder gelingt es, beim Freigeben des Objekts ALLE (Objekt-)Variablen auf nil zu setzen,
oder du verwendest Interfacezeiger oder du gehst zurück auf Anfang und überlegst dir was ganz neues.

Phoenix 9. Nov 2005 10:05

Re: Bin ich schon zerstört?
 
Japp, das kann ic´h nur unterschreiben. Wenn Du eine Referenz auf ein bereits zerstörtes Objekt hältst und die von der Zerstörung nichts mitbekommt, dann ist vorher irgendwas schief gelaufen. Du solltest das Design nochmal überdenken und tatsächlich auf Referenzzähler zurückgreifen.

alzaimar 9. Nov 2005 11:29

Re: Bin ich schon zerstört?
 
Zitat:

Zitat von Sidorion
Das mit den Referenzzählern geht nicht, weil
a) viel zu viel Aufwand (wird nicht bezahlt)

So ist das nunmal, wenn man einen 'falschen' Ansatz hat.
Du kannst die Konstruktoren Create und den Destruktor Destroy in '_create' und '_Destroy' umbenennen.
Create wird eine Class function, die Dir das eine Objekt liefert und den ref-zähler hochsetzt.
Destroy wird eine einfache Methode, die den RefCount wieder runterzählt und ggf das interne Objekt freigibt
Aufwand: 10 minuten (wenns klappt :mrgreen: ). Sollte aber, sofern Du sauber programmiert hast. Wenn nicht, goto a)

DerDan 9. Nov 2005 12:07

Re: Bin ich schon zerstört?
 
das find ich persönlich komisch:


erst um Hilfe fragen und dann aber doch nix ändern wollen.

Das erinnert mich an meinen Chef der sagt auch immer:

"beheb mal den Fehler, änder aber um himmels willen nichts am code"

und da steh ich dann...



mfg

MaBuSE 9. Nov 2005 12:40

Re: Bin ich schon zerstört?
 
Zitat:

Zitat von DGL-luke
Delphi-Quellcode:
if assigned(myobj) then
 dosomething;
wenn der zeiger anständig nil gesetzt wurde nach dem zerstören.

Zitat:

Zitat von Sidorion
@DGL-Luke: darum ist Assigned(MyObj) in dem Falle nach wie vor true, das ist ja das Problem. Wenn nicht, würd ich die Methode ja nicht mehr rufen.

Das ist das was er mit "wenn der Zeiger anschtändig nil gesetzt wurde" meinte.

Ich habe mir angewöhnt Objekte immer wie folgt freizugeben:
Delphi-Quellcode:
...
  myObject.Free;
  myObject := nil;
...
Dann funktioniert auch der oben angegebene Code wieder. (asigned prüft auf nil)

Free prüft auch auf nil, deshalb ist folgender Code fehlerhaft:
Delphi-Quellcode:
...
  myObject := TmyObject.Create;
...
  myObject.Free;

  myObject.Free; // hier gibts Exception !!!
...
Folgender code läuft hingegen fehlerfrei:
Delphi-Quellcode:
...
  myObject := TmyObject.Create;
...
  myObject.Free;
  myObject := nil;

  myObject.Free;   // kein Problem, da destroy nur aufgerufen wird, wenn <> nil
  myObject := nil; // diese 2. nil-Zuweisung ist überflüssig,
                    // aber ich kombiniere immer Free mit nil Zuweisung ;-)
...

Wenn Dir das zuviel Tipparbeit ist, kannst Du auch FreeAndNil verwenden.
Delphi-Quellcode:
...
  FreeAndNil(myObject);
...
(ist in SysUtils definiert)
Delphi-Quellcode:
{ *********************************************************************** }
{                                                                         }
{ Delphi / Kylix Cross-Platform Runtime Library                          }
{ System Utilities Unit                                                  }
{                                                                         }
{ Copyright (c) 1995-2002 Borland Softwrare Corporation                  }
{                                                                         }
{ *********************************************************************** }

unit SysUtils;
...
procedure FreeAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free;
end;
...


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:22 Uhr.
Seite 2 von 3     12 3      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz