Delphi-PRAXiS
Seite 1 von 2  1 2   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi FreeAndNil macht Probleme (https://www.delphipraxis.net/205601-freeandnil-macht-probleme.html)

Benmik 27. Sep 2020 14:20

Delphi-Version: 10.3 Rio

FreeAndNil macht Probleme
 
Ich habe hier eine Unit mit einer Klasse, von TObject abgeleitet, nichts Besonderes mit einer Anzahl von Feldern und Prozeduren/Funktionen, die ungefähr 10 Klassen der gleichen Unit beherbergt. Diese Unit hat
Delphi-Quellcode:
procedure Clear;
procedure Free;
constructor Create;
Diese Unit habe ich nun in mein Programm eingebunden. Alles lief ohne Probleme, bis es auf einmal wüste Meldungen von FastMM hagelte, Hunderte von Speicherlecks. Ich habe mir einen Wolf gesucht, aber die Objektinstanz wurde immer ordnungsgemäß freigegeben. Endlich kam ich auf die Idee, einen Haltepunkt bei
Delphi-Quellcode:
Free
zu setzen.

Und da kam Folgendes raus: Wenn ich
Delphi-Quellcode:
Objekt.Free
geschrieben hatte, wurde die Prozedure auch durchlaufen. Aber nicht bei
Delphi-Quellcode:
FreeAndNil(Objekt)
. Als ich alles zu
Delphi-Quellcode:
Free
geändert hatte, gab FastMM sofort Ruhe.

Ist sowas bekannt? Ich habe meiner Erinnerung nach nichts an den Projektoptionen geändert, und in dem sonstigen Code kommt häufig
Delphi-Quellcode:
FreeAndNil
vor. Was sagen die Experten?

Vielleicht sollte ich noch sagen, dass mir meine Rio 10.3.3-Installation sowieso etwas merkwürdig vorkommt. Die roten Fehler-Krickel fehlen; Haltepunkte werden manchmal ignoriert, bis ich neu erzeuge; und bei einem Haltepunkt ist der Debugger nicht selten schon deutlich weiter. STRG + # funktioniert laufend nicht (-> Rechtsklick hilft). Vermutlich sagen jetzt alle, öh, neu installieren, aber kann das mit FreeAndNil so einfach sein?

Bernhard Geyer 27. Sep 2020 14:27

AW: FreeAndNil macht Probleme
 
Delphi-Quellcode:
procedure Free;
ganz klar. Implementierungsfehler.
Du überschreibst Free ohne anzugeben das du die bestehende Methode überschreiben willst (Weiß jetzt nicht ob Free als virtuel/dynamic definiert).
Auch sollte man nicht Free überschreiben sondern den Destruktor Destroy.

Benmik 27. Sep 2020 14:35

AW: FreeAndNil macht Probleme
 
Delphi-Quellcode:
TObject.Free
kann nicht überschrieben werden, da es keine virtuelle Methode ist. Auch füge ich natürlich ein "inherited" an. Das alles erklärt aber nicht, warum meine Methode bei
Delphi-Quellcode:
Free
aufgerufen wird, bei
Delphi-Quellcode:
FreeAndNil
aber nicht.
Delphi-Quellcode:
FreeAndNil
ist doch überhaupt nichts anderes als ein Free mit nachfolgendem
Delphi-Quellcode:
 := nil
.
Und warum
Delphi-Quellcode:
Destroy
??

himitsu 27. Sep 2020 14:44

AW: FreeAndNil macht Probleme
 
FreeAndNil kennt "Dein" Free nicht!
Wie soll es das dann aufrufen?

Nunachmal: Überschreibe Destroy, welches vom Free und somit auch vom FreeAndNil aufgerufen wird.

Genauso wie man beim TComponent alle Initialisierungen ins überschriebene Create(Owner) reinmachen muß, denn nur Dieses kennt die VCL/FMX und nur das kann beim Laden der Form aufgerufen werden.
"Zusätzliche" Create, mit weiteren Parametern für ein manuelles Erstellen, sind dort OK, aber beim Free/Destroy gibt es da keine Kompromisse/Alternativen.

Benmik 27. Sep 2020 14:57

AW: FreeAndNil macht Probleme
 
OK, folgende Änderungen:
Delphi-Quellcode:
      procedure Clear;
      destructor Destroy; override;
      constructor Create;
Delphi-Quellcode:
destructor TEXIF.Destroy;
begin
  FreeAndNil(FDStream);
  inherited;
end;
Jetzt meldet sich FastMM mit der schon bekannten langen Liste von Lecks, obwohl es kein
Delphi-Quellcode:
FreeAndNil
gibt. Mit dem einfachen bisherigen
Delphi-Quellcode:
Free
sagt FastMM nichts.

EDIT: Bitte um Verzeihung, funktioniert doch. In
Delphi-Quellcode:
Destroy
hätte viel mehr stehen müssen als nur der FDStream.
Ich danke euch beiden. Verstehe es aber trotzdem nicht ganz:
Delphi-Quellcode:
FreeAndNil
setzt die Referenz auf nil und ruft dann
Delphi-Quellcode:
Free
auf. Wieso muss der Compiler dann mein (?)
Delphi-Quellcode:
FreeAndNil
kennen?

Und nebenbei: Wie machst du den durchgestrichenen Text, Himitsu?

jfheins 27. Sep 2020 15:24

AW: FreeAndNil macht Probleme
 
Zitat:

Zitat von Benmik (Beitrag 1474395)
Ich danke euch beiden. Verstehe es aber trotzdem nicht ganz:
Delphi-Quellcode:
FreeAndNil
setzt die Referenz auf nil und ruft dann
Delphi-Quellcode:
Free
auf. Wieso muss der Compiler dann mein (?)
Delphi-Quellcode:
FreeAndNil
kennen?

Du hast ja Free nicht überschrieben (weil unmöglich - überschreiben geht ja nur bei virtuellen Methoden)

Wenn du dir FreeAndNil anguckst, steht da:
Delphi-Quellcode:
procedure FreeAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free;
end;
D.h. .Free wird auf eine Variable von Typ TObject aufgerufen. Und das ist OK, denn TObject is ja hinreichend.

Nur ohne das override wird hier auch immer TObject.Free aufgerufen. Nur bei virtuellen Methoden wird hier nachgeuckt, ob die Methode überschrieben wurde.

himitsu 27. Sep 2020 15:39

AW: FreeAndNil macht Probleme
 
Zitat:

Zitat von jfheins (Beitrag 1474398)
Du hast ja Free nicht überschrieben (weil unmöglich - überschreiben geht ja nur bei virtuellen Methoden)

Free braucht auch nicht viruell zu sein. Am Ende wird sowieso Destroy aufgerufen, also reicht das vollkommen aus.
Wenn auf einem Pfad mehrere Methoden überscheibbar sind, dann kommt eh nur Chaos raus wenn ein Teil hier und ein Teil da.

Sowas gibt es teilweise in der VCL/RTL und das macht keinen Spaß.
Bei Constructoren einiger Klassen, im TStream mit SetSize und Co. oder z.B. beim Assign und AssingTo des TPersistent/TComponent.
Abgesehn davon dass man sich dann selbst nur schwer entscheiden kann, wo man nun was rein machen muß.


Durchgestrichen? Hab ich hier doch garnichts, aber wenn, dann wäre es ein [S]Geheinis[/S]. :lol:
Oder meinst das Unterstrichen der Akronyme ala BBCode?

Benmik 27. Sep 2020 15:48

AW: FreeAndNil macht Probleme
 
@jfheins: Das heißt, dass durch den Umweg über das Casting zu TObject (damit in jedem Fall Nil geschieht) direkt die Original-Methode Free von TObject aufgerufen und dadurch mein Free (mangels override) umgangen wird? Tricky, würde ich sagen. Warum ist denn dann TObject.Free nicht virtuell? Jedenfalls wieder eine Erkenntnis.
Von Destroy hatte ich die Finger gelassen, weil in der OH steht, man solle Destroy nicht direkt aufrufen. Aber es stimmt, von nicht überschreiben stand da nichts.

@Himitsu: Mist, das hatte ich bei meiner Suche nicht gesehen ausprobiert! Danke!

jfheins 27. Sep 2020 16:01

AW: FreeAndNil macht Probleme
 
Zitat:

Zitat von Benmik (Beitrag 1474401)
@jfheins: Das heißt, dass durch den Umweg über das Casting zu TObject (damit in jedem Fall Nil geschieht) direkt die Original-Methode Free von TObject aufgerufen und dadurch mein Free (mangels override) umgangen wird?

Ja, genau. Das passiert bei allen Methoden, die nur verdeckt werden. (Verdecken = Neue Definition aber ohne override)

=> Verdecken sollte vermieden werden.

Zitat:

Tricky, würde ich sagen. Warum ist denn dann TObject.Free nicht virtuell? Jedenfalls wieder eine Erkenntnis.
Weil .Destroy ja schon virtuell ist damit genau eine einzige Stelle existiert, wo man Freigabecode unterbringen sollte.

Free hingegen macht ja nur den nil check mehr, und damit war die Methode aus Sicht der Entwickler einfach fertig.

Benmik 27. Sep 2020 16:26

AW: FreeAndNil macht Probleme
 
Einleuchtend. Da hantiert man eine Ewigkeit mit Free und kommt erst jetzt zu einem Blick hinter die Kulissen.

Wie gesagt, ich hatte Destroy aufgrund der Warnung in der OH immer so etwas wie eine Methode (so wie eine abstrakte) gesehen, die man nicht direkt anfassen sollte.


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:45 Uhr.
Seite 1 von 2  1 2   

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