Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free (https://www.delphipraxis.net/80803-unterschied-zwischen-freeandnil-objekt-und-objekt-free.html)

peacemoon 15. Nov 2006 15:10


Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Kann jemand mir erklären, welchen Unterschied gibt es zwischen FreeAndNil(Objekt) und Objekt.Free?

mkinzler 15. Nov 2006 15:11

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
FreeAndNil ist
Delphi-Quellcode:
Objekt.Free;
Objekt := Nil;

pertzschc 15. Nov 2006 15:15

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Sofern ich es verstanden habe:
Du hast eine Variable die Du mit Create einer Klasse erzeugt hast.

Delphi-Quellcode:
myVar := TMyVar.Create;
Delphi-Quellcode:
myVar.Free
gibt nur den reservierten (und belegten) Speicherbereich frei, auf den myVar zeigt.
Der Zeiger selber hat danach immer noch die Adresse des Speicherbereiches.

Delphi-Quellcode:
FreeAndNil(myVar);
gibt den reservierten (und belegten) Speicherbereich frei und setzt zusätzlich
der Zeiger von myVar auf nil.
Damit kannst Du hinterher sauber mit (myVar = nil) prüfen.

Gruß,
Christoph

semo 15. Nov 2006 15:55

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
zusatz: freeandnil kannst du auch mit einem nicht erzeugten objekt aufrufen ohne das es knallt, sprich du musst vorher nicht auf nil prüfen umd das objekt freizugeben

hoika 15. Nov 2006 16:49

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Hallo,

Vorsicht mit solchen Behauptungen.
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  Button: TButton;
begin
  FreeAndNIL(Button); // Schutzverletzung !
end;
Was du meintest war, dass .Free auch bei NIL-Objekten klappt.

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  Button: TButton;
begin
  Button:= NIL;
  Button.Free; // OK
end;
Was das etwas undurchsichtig macht ist, dass Klassenvariablen
automatisch initialisiert werden, Zeiger und damit auch Objekte also z.B. NIL sind.

Das FreeAndNIL ist einfach die Zusammenfassung von 2 Befehlen.


Heiko

Khabarakh 15. Nov 2006 16:53

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von computer-glossar.de
zusatz: freeandnil kannst du auch mit einem nicht erzeugten objekt aufrufen ohne das es knallt, sprich du musst vorher nicht auf nil prüfen umd das objekt freizugeben

Nope, das ist schon in Free eingebaut.

[edit]
Zitat:

Zitat von hoika
Schutzverletzung !

Muss nicht sein, vermeiden sollte man solchen Code trotzdem ;) .
[/edit]

SirThornberry 15. Nov 2006 16:55

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von Khabarakh
Zitat:

Zitat von computer-glossar.de
zusatz: freeandnil kannst du auch mit einem nicht erzeugten objekt aufrufen ohne das es knallt, sprich du musst vorher nicht auf nil prüfen umd das objekt freizugeben

Nope, das ist schon in Free eingebaut.

[edit]
Zitat:

Zitat von hoika
Schutzverletzung !

Muss nicht sein, vermeiden sollte man solchen Code trotzdem ;) .
[/edit]

Jein, es geht nich darum das es nihct erzeugt sein muss sondern darum das die Instanzvariable nil ist.

Khabarakh 15. Nov 2006 17:00

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Hm? Ob das Objekt instanziiert wurde, kann weder Free noch FreeAndNil erkennen. Sie können nur den Pointer auf nil prüfen, aber das machen eben beide.
Man könnte höchstens sagen, dass bei einem Aufruf von FreeAndNil ein weiteres Free(AndNil) nicht fehlschlagen wird.

jbg 15. Nov 2006 17:55

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von Khabarakh
Man könnte höchstens sagen, dass bei einem Aufruf von FreeAndNil ein weiteres Free(AndNil) nicht fehlschlagen wird.

Sofern die Variable nicht aus ihrem Sichtbarkeitsbereich (scope) tritt und somit nicht mehr erreichbar ist. Für lokale Variablen ist FreeAndNil z.B nicht notwendig, wenn zu einem späteren Zeitpunkt in der Funktion nicht mehr auf diese Variable zugegriffen wird. Man kann es nämlich mit FreeAndNil auch übertreiben, wie es bei den Indy-Komponenten der Fall ist.

pertzschc 15. Nov 2006 18:06

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von jbg
Für lokale Variablen ist FreeAndNil z.B nicht notwendig, wenn zu einem späteren Zeitpunkt in der Funktion nicht mehr auf diese Variable zugegriffen wird.

Wie meinst Du das? Wird das .Free einer lokales Variable am Ende der Prozedur automatisch aufgerufen oder wird nur der Zeiger auf nil gesetzt?

mkinzler 15. Nov 2006 18:15

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Wie meinst Du das? Wird das .Free einer lokales Variable am Ende der Prozedur automatisch aufgerufen oder wird nur der Zeiger auf nil gesetzt?
.Free ruft .Destroy auf, gibt also den Speicher frei ohne die Referenz auf Nil zu setzen

Khabarakh 15. Nov 2006 18:20

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von pertzschc
Zitat:

Zitat von jbg
Für lokale Variablen ist FreeAndNil z.B nicht notwendig, wenn zu einem späteren Zeitpunkt in der Funktion nicht mehr auf diese Variable zugegriffen wird.

Wie meinst Du das? Wird das .Free einer lokales Variable am Ende der Prozedur automatisch aufgerufen oder wird nur der Zeiger auf nil gesetzt?

Tritt eine Variable aus dem Scope, geht ihr Inhalt verloren. also ist es egal, ob der Pointer nun noch auf das (hoffentlich) freigegebene Objekt zeigt oder mit FreeAndNil auf nil gesetzt wurde.

Zitat:

Zitat von jbg
Zitat:

Zitat von Khabarakh
Man könnte höchstens sagen, dass bei einem Aufruf von FreeAndNil ein weiteres Free(AndNil) nicht fehlschlagen wird.

Sofern die Variable nicht aus ihrem Sichtbarkeitsbereich (scope) tritt und somit nicht mehr erreichbar ist.

Ich weiß, was du meinst, aber auf eine aus dem Scope getretene Variable lässt sich schlecht eine Prozedur anwenden :zwinker: .

Hansa 15. Nov 2006 19:52

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von jbg
..Man kann es nämlich mit FreeAndNil auch übertreiben...

Das könnte man wirklich unterschreiben. :zwinker: Das Speichermanagement von Delphi ist nicht schlecht und macht vieles automatisch. Die Frage hat sich hier aber auch gestellt. Es gibt Destroy, Free, FreeAndNil. Genau ! Wo liegt jetzt der Unterschied ? Selbst mit Borland-Unterstützung war das nicht genau zu klären, was man nun am besten wo und wann verwenden soll. Bei allen drei Alternativen gab es hier und da einen Fehler. Je nach Konstellation.

Ist schon etwas länger her, aber ich glaube das auf NIL setzen reichte nicht aus, sofern darauf geprüft wird und ein zu entfernendes TObject ist nicht da. Bevor mir einen einen Strick daraus dreht : das nächste ist ohne Gewähr. Ist das TObject in keinster Weise initialisiert, dann kommen vermutlich Fehler. Folgende Konstruktion lief bisher ohne jeden Fehler :

Delphi-Quellcode:
if Objekt <> nil then begin
  Objekt.Free;
  Objekt := nil;
end;
Das FreeAndNil könnte da vielleicht eine Zeile sparen aber nicht ohne die Abfrage <> nil ! Damit wird aber jetzt nicht rumgespielt, denn es gilt : "Never change a running system".

mkinzler 15. Nov 2006 19:54

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Die Abfrage auf Nil macht IMHO FreeAndNil

Muetze1 15. Nov 2006 20:14

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
FreeAndNil() überprüft nicht, aber Free macht dies. Und Free wird aufgerufen. Somit lässt sich's Hansa's abschliessendes Codestück durch einen einzigen FreeAndNil() Aufruf ersetzen, der gleiches macht.

FreeAndNil():
Delphi-Quellcode:
procedure FreeAndNil(var Obj);
var
  P: TObject;
begin
  P := TObject(Obj);
  TObject(Obj) := nil; // clear the reference before destroying the object
  P.Free;
end;
Free Methode:
Delphi-Quellcode:
procedure TObject.Free;
asm
        TEST   EAX,EAX     // If not Assigned Then
        JE     @@exit      //   goto exit

        MOV    ECX,[EAX]   // get virtual methode table
        MOV    DL,1   
        CALL   dword ptr [ECX].vmtDestroy  // call actual Destroy methode implementation for the instance
@@exit:
end;
Einer von den Geeks hier im Forum könnte uns mal aufklären, warum in DL unbedingt eine 1 stehen muss beim Aufruf von Destroy

Hansa 15. Nov 2006 20:24

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von mkinzler
Die Abfrage auf Nil macht IMHO FreeAndNil

Ne, macht sie nicht :

Delphi-Quellcode:
procedure FreeAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free;
end;
Um Zeile 16275 :shock: in Sysutils.pas (D7) Eine Abfrage auf NIL ist da nicht zu sehen. Warum auch immer, aber nur der vorher gepostete Code hat sich als wasserdicht herausgestellt.

Muetze1 15. Nov 2006 20:26

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von Hansa
Um Zeile 16275 :shock: in Sysutils.pas (D7) Eine Abfrage auf NIL ist da nicht zu sehen. Warum auch immer, aber nur der vorher gepostete Code hat sich als wasserdicht herausgestellt.

Siehe mein Post. FreeAndNil() macht keine Abfrage sondern ruft Free auf. Und Free macht diese Abfrage.

Hansa 15. Nov 2006 20:30

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Mütze, das ist fies. :mrgreen: Erst halb schreiben und dann nachträglich editieren, während ich die relevante Stelle im Source suche. :P

Muetze1 15. Nov 2006 20:50

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von Hansa
Mütze, das ist fies. :mrgreen: Erst halb schreiben und dann nachträglich editieren, während ich die relevante Stelle im Source suche. :P

Sorry, aber ich hatte erstmal noch überlegt, ob ich den Teil poste, da es ja Borland gehört. Aber ich habe mich erst nachträglich dafür entschieden.

Hinweis: Die Kommentare vom Assemblercode sind von mir...

Hawkeye219 15. Nov 2006 21:00

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Hier ist noch etwas von Borland:

Zitat:

Zitat von Delphi-Sprachreferenz, Abschnitt 'Ablaufsteuerung'
Konstruktoren und Destruktoren verwenden dieselben Aufrufkonventionen wie die anderen Methoden. Es wird jedoch ein zusätzlicher Boolescher Flag-Parameter übergeben, der den Kontext des Konstruktor- oder Destruktoraufrufs anzeigt.

Der Wert False im Flag-Parameter eines Konstruktoraufrufs zeigt an, dass der Konstruktor über ein Instanzobjekt oder mit dem Schlüsselwort inherited aufgerufen wurde. In diesem Fall verhält sich der Konstruktor wie eine normale Methode. Der Wert True im Flag-Parameter eines Konstruktoraufrufs zeigt an, dass der Konstruktor über eine Klassenreferenz aufgerufen wurde. In diesem Fall erzeugt der Konstruktor eine Instanz der mit Self referenzierten Klasse und gibt in EAX eine Referenz auf das neu erzeugte Objekt zurück.

Der Wert False im Flag-Parameter eines Destruktoraufrufs zeigt an, dass der Destruktor mit dem Schlüsselwort inherited aufgerufen wurde. In diesem Fall verhält sich der Destruktor wie eine normale Methode. Der Wert True im Flag-Parameter eines Destruktoraufrufs zeigt an, dass der Destruktor über ein Instanzobjekt aufgerufen wurde. In diesem Fall gibt der Destruktor die mit Self bezeichnete Instanz frei, bevor er beendet wird.

Der Flag-Parameter verhält sich so, als ob er vor allen anderen Parametern deklariert worden wäre. Bei der Konvention register wird er im Register DL übergeben. Bei pascal erfolgt die Übergabe vor allen anderen Parametern. Bei den Konventionen cdecl, stdcall und safecall wird er direkt vor dem Parameter Self übergeben.

Der Wert von DL muss deshalb vor der Beendigung des Programms wiederhergestellt werden, damit BeforeDestruction oder AfterConstruction ordnungsgemäß aufgerufen werden kann.

Gruß Hawkeye

pertzschc 15. Nov 2006 21:30

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Interessant was sich aus der Frage alles so ergibt!

Aber meine Detailfrage ist nun immer noch nicht vollständig beantwortet:
Ich habe eine Klasse TMyVar mit einem Member vom Typ TStringlist. Diese Member wird im Konstruktor meiner Klasse ordnungsgemäß erzeugt. Jetzt benutze ich die Klasse in einer function/procedure:
Delphi-Quellcode:
procedure TForm1.Beispiel;
var
  MyVar: TMyVar;
begin
  MyVar:=TMyVar.Create;
  // hier passiert dann mal was...
  ...
  // hier ist das Ende der Procedur:
  FreeAndNil(MyVar); // a)
  MyVar.Free;       // b)
                     // c)
end;
Ist nun Variante a), b) notwendig oder muss man c) gar nichts damit machen, da am Ende der Methode die lokale Variable myVar automatisch einen .Free-Aufruf erhält?

Gruß,
Christoph

Luckie 15. Nov 2006 21:36

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von pertzschc
oder muss man c) gar nichts damit machen, da am Ende der Methode die lokale Variable myVar automatisch einen .Free-Aufruf erhält?

Delphi hat keine GarbageCollection. Die Variable wird ungültig, aber der Speicher ist noch reserviert, ergo muss ein Feee erfolgen.

3_of_8 15. Nov 2006 21:42

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Kann man bei Records, Strings und dynamischen Arrays nicht von Garbage Collection sprechen?

Flocke 15. Nov 2006 22:00

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von Muetze1
Einer von den Geeks hier im Forum könnte uns mal aufklären, warum in DL unbedingt eine 1 stehen muss beim Aufruf von Destroy

Jeder Konstruktor und Destruktor bekommt von Delphi noch einen impliziten zusätzlichen Parameter mit der Info, ob der Speicher für das Objekt angefordert/freigegeben werden muss oder nicht. Beim direkten Aufruf eines Konstruktors/Destruktors ist dieser Parameter 1, bei inherited-Aufrufen 0.

Muetze1 15. Nov 2006 22:09

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von Flocke
Zitat:

Zitat von Muetze1
Einer von den Geeks hier im Forum könnte uns mal aufklären, warum in DL unbedingt eine 1 stehen muss beim Aufruf von Destroy

Jeder Konstruktor und Destruktor bekommt von Delphi noch einen impliziten zusätzlichen Parameter mit der Info, ob der Speicher für das Objekt angefordert/freigegeben werden muss oder nicht. Beim direkten Aufruf eines Konstruktors/Destruktors ist dieser Parameter 1, bei inherited-Aufrufen 0.

Danke, aber das hat Hawkeye219 mit einem vortrefflichen Post aus der Borland Hilfe/Referenz schon geklärt.

hoika 16. Nov 2006 05:08

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Hallo Kha..,

was heisst, muss nicht sein ?
Schon klar, dass man sowas vermeiden sollte.

Es ist aber so, dass FreeAndNIL nicht initialisierte Objekte
nicht erkennen kann.
Dafür gibt es ja dass NIL setzen.

Zum "Was sollte man nehmen".

Destroy nie direkt aufrufen.
Zum Freigeben .Free benutzen, falls das Objekt später nicht mehr benutzt wird,
weil es z.B. eine lokale Variable ist.
FreeAndNIL fasst 2 Befehle zusammen (Free and NIL, wer hätte das gedacht ;) ),
macht also Sinn, wenn das Objekt mehrfach verwendet werden kann.

Wir ein Objekt über lokale Variable erzeugt und nicht freigegeben,
bleibt der Speicher belegt, bis das Programm beendet wird (nicht unter Win9X).
Wenn ich also so eine Prozedur 1 Mio. mal im Programm benutze,
frisst die jedes mal Speicher.
Und irgendwann sind auch 2 Gig weg.


Heiko

Khabarakh 16. Nov 2006 12:17

Re: Unterschied zwischen FreeAndNil(Objekt) und Objekt.Free
 
Zitat:

Zitat von hoika
was heisst, muss nicht sein ?

Die Wahrscheinlichkeit ist zwar eher gering, aber Pointer-Gefuchtel kann entweder nicht-reservierten Speicher treffen -> AV oder eben zufällig doch auf einen reservierten Teil zeigen. Was allerdings noch schlimmer ist, da sich das Programm im Gegensatz zum ersten Fall nach einem Free- oder sonstigen Aufruf dann in einem unvorhersagbaren, inkonsistenten (Speicher-)Zustand befindet.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:54 Uhr.

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