![]() |
2 StringListen try finally richtig anwenden
Hallo,
irgendwann hatte ich hier mal gelesen, dass der folgende Code richtig ist
Delphi-Quellcode:
Grund: Wenn hinter SL1 := TStringList.Create; was passiert, werden beide StringListen korrekt freigegeben ,
var
SL1, SL2: TStringList; begin SL1 := nil; SL2 := nil; try SL1 := TStringList.Create; SL2 := TStringList.Create; finally FreeAndNil(SL1); FreeAndNil(SL2); end; genauer SL1 wird freigegeben, SL2 ist ja noch nil; Jetzt habe ich den Code aber mal durch den PAL (Pascal Analyzer) gejagt und der sagt, dass das SL1 := nil; SL2 := nil; unnützer Code ist. Vorgeschlagen wird
Delphi-Quellcode:
Was meint ihr?
var
SL1, SL2: TStringList; begin SL1 := TStringList.Create; SL2 := TStringList.Create; try finally SL.Free); SL2.Free; end; |
AW: 2 StringListen try finally richtig anwenden
Delphi-Quellcode:
Wohl dann eher so (Erzeugung der Klassen außerhalb von try ... finally ... end). Über FreeAndNil() wollen wir hier nicht diskutieren ...
var
SL1, SL2: TStringList; begin SL1 := TStringList.Create; SL2 := TStringList.Create; try // tue irgendetwas finally FreeAndNil(SL1); FreeAndNil(SL2); end; |
AW: 2 StringListen try finally richtig anwenden
Zitat:
Da die Methode/Prozedur danach sowieso beendet wird ist das Setzen auf Nil nicht unbedingt nötig. |
AW: 2 StringListen try finally richtig anwenden
Zitat:
|
AW: 2 StringListen try finally richtig anwenden
Also hiermit kannst du nix falsch machen, aber auch ich mache das nicht immer :mrgreen:
Delphi-Quellcode:
var
SL1, SL2: TStringList; begin SL1 := TStringList.Create; try SL2 := TStringList.Create; try // Code finally FreeAndNil(SL2); end; finally FreeAndNil(SL1); end; end; |
AW: 2 StringListen try finally richtig anwenden
Bei Mehrfach-Erzeugungen hast Du natürlich Recht ... man kann es noch weiter "Theorisieren" und das Ganze noch in ein
Delphi-Quellcode:
einbetten.
try ... except ... end
Und bei einfachen Klassen wie TStringList läuft sicherlich nichts schief. |
AW: 2 StringListen try finally richtig anwenden
Zitat:
Ich war immer der Meinung, dass
Delphi-Quellcode:
prüft ob
Free
Delphi-Quellcode:
ist und nicht mehr.
Self = nil
Eine lokale Variable ist immer nicht initialisiert und kann jeden beliebigen Wert enthalten. Um einen bestimmten Wert zu garantieren muss die Variable initialisiert werden. Es muss also minimal so aussehen um sicher zu sein, egal was irgendein Analyzer da von sich gibt
Delphi-Quellcode:
procedure foo;
var sl1, sl2: TStringList; begin sl2:= nil; sl1:= TStringList.Create(); try sl2:= TStringList.Create(); ... finally sl2.Free(); sl1.Free(); end; end; |
AW: 2 StringListen try finally richtig anwenden
|
AW: 2 StringListen try finally richtig anwenden
Zitat:
|
AW: 2 StringListen try finally richtig anwenden
Ich initialisiere die Variablen auch meistens direkt nach begin, und bekomme diese blöden Compilermeldungen
das dies überflüssig sein. Aber wenn es überflüssig ist, dann müssten ja alle Variablen schon vorinitialisiert sein.
Delphi-Quellcode:
Kann man sich etwa darauf verlassen ?
procedure foo;
var sl1, sl2: TStringList; begin //<-- Ist ab hier sl1 und sl2 hier nicht auch schon mit nil initialisiert, also SOLLTE nichts passieren ? sl1:= TStringList.Create(); //--> passiert hier eine Exception ist sl2 = nil ? sl2:= TStringList.Create(); try ... finally sl2.Free(); sl1.Free(); end; end; Oder was sollen die Meldungen dann bedeuten (womöglich einfach nur bugs ? Rollo |
AW: 2 StringListen try finally richtig anwenden
Zitat:
Delphi-Quellcode:
Mal ehrlich, mit noch mehr verschachtelten try...finally's wird der Code einfach nur grausam unübersichtlich. Und wenn schon beim Create eine Exception auftritt, ist eh irgendwas ganz gewaltig im Argen.
v1 := xxx.create;
v2 := xxx.create; try finally v1.Free; v2.Free; end; |
AW: 2 StringListen try finally richtig anwenden
Meine Klassen haben im Create so gut wie immer einen Guard Abschnitt, der eine Exception wirft, wenn die Argumente im Create unsinnig sind, meine Klasse mit diesen Werten gar nicht arbeiten kann.
Ein Create ist auch nur eine gewöhnliche Methode die auch eine Exception werfen kann. Wenn ich nicht auf MemLeaks stehe, dann implementiere ich es richtig (das eben keine MemLeaks entstehen können). |
AW: 2 StringListen try finally richtig anwenden
@Rollo62
lokale Variablen sind per Definition nicht initialisiert. Man kann sich bezüglich des Wertes auf gar nichts verlassen. Die Compilermeldung ist in diesem speziellen Fall Schwachfug |
AW: 2 StringListen try finally richtig anwenden
Initialisieren muß man Variablen (vorallem die Lokalen) nur, wenn man sie auswerten will/muß, bevor etws zugewiesen werden konnte.
Grundsätzlich: * Alle Variablen müssen vor dem Try initialisiert werden (gilt vorallem für lokale Variablen) * maximal 1 Create dürfte vor das Try (wenn es da schon knallt wird Nachfolgendes nicht ausgeführt) * im Free kann man nur etwas zusammenfassen, wenn es dort keine Fehler geben kann, bzw. maximal beim letzten Befehl da drin Also ob sich mehrere Try-Finally verbinden lassen, hängt eigentlich vom Finally ab, aber man kann Try-Finally auch da unten verschachteln. Zitat:
Delphi-Quellcode:
Probleme gibt.
sl1:= TStringList.Create();
Delphi-Quellcode:
sl1 := nil;
sl2 := nil; try sl1 := TStringList.Create; sl2 := TStringList.Create; ... finally sl2.Free; sl1.Free; end;
Delphi-Quellcode:
sl1 := TStringList.Create;
try sl2 := TStringList.Create; ... finally sl2.Free; sl1.Free; end;
Delphi-Quellcode:
sl1 := TStringList.Create;
try sl2 := TStringList.Create; ... finally try sl2.Free; finally sl1.Free; end; end;
Delphi-Quellcode:
Letztendlich bassiert alles auf den oben genannten Punkten.
sl1 := TStringList.Create;
try sl2 := TStringList.Create; try ... finally sl2.Free; end; finally sl1.Free; end; Also wenn die zutreffen, dann isses OK. Selbst das wäre "richtig"
Delphi-Quellcode:
z.B. bei einer TStringList geh ich grundsätzlich davon aus, daß das Freigeben immer funktioniert (so lange der Zeiger gültig ist)
sl1 := TStringList.Create;
try sl2 := TStringList.Create; except sl1.Free end; try ... finally try sl2.Free; finally sl1.Free; end; end; // oder sl1 := nil; try sl1 := TStringList.Create; sl2 := TStringList.Create; except sl1.Free end; try ... finally try sl2.Free; finally sl1.Free; end; end; und demnach kann ich da auch mehrere Free zusammen in ein Finally schreiben. Sollte es dort dennoch knallen, dann ist perse das Programm nicht mehr lauffähig und eine bessere Fehlerbehandlung ist eh nicht mehr nötig. (z.B. nach einem Buffer-Overrun) |
AW: 2 StringListen try finally richtig anwenden
Das sehe ich auch so.
Allerdings beim Debuggen scheinen die Variablen bei Objekten (immer ?) korrekt genullt zu sein, hab allerdings nicht getestet ob das generell so ist. Bei anderen Variablentypen ist das jedenfalls nicht der Fall. Ich dachte es gäbe dazu vielleicht eine globable Compilereinstellung. Leider kann man die "unützen" Hints nicht gezielt abschalten, nur evtl. mit einem {$HINTS Off} vor solchen Funktionen, was aber auch nicht machen möchte. Mich stören die Dinger jedenfalls gewaltig. Rollo |
AW: 2 StringListen try finally richtig anwenden
@himi :thumb:
(hab mal still und heimlich meinen Beitrag editiert, evtl. merkt es ja keiner :stupid:) |
AW: 2 StringListen try finally richtig anwenden
Debuggen: Wenn es gibt einige Typen, die werden automatisch initialisiert. (z.B. strings)
Und dann kommt es halt darauf an wo diese Variablen liegen (auf'm Heap, also z.B. Global oder in einer Klasse) oder auf'm Stack und ob oder was vorher an der Stelle gespeichert war. |
AW: 2 StringListen try finally richtig anwenden
Hallo,
das Verschachteln hatte ich früher auch gemacht, aber: wie Sir Rufo richtig sagt, das wird unübersichtlich, trotz 250 Zeichen pro Zeile ;) Wir haben jetzt eine neue Version von PAL bestellt, mal sehen, was der so anzeigt ... < Leider kann man die "unützen" Hints nicht gezielt abschalten, > < nur evtl. mit einem {$HINTS Off} vor solchen Funktionen, was aber auch nicht machen möchte. > < Mich stören die Dinger jedenfalls gewaltig. > Dann jag mal dein Projekt durch den PAL, der zeigt dir Sachen an ... Also ich finde die Hints gut. Ich versuche immer, die gegen 0 Laufen zu lassen. |
AW: 2 StringListen try finally richtig anwenden
Zitat:
den PAL nutze ich leider immer noch viel zu wenig, den finde ich an vielen Stellen ebenfalls eine große Hilfe. |
AW: 2 StringListen try finally richtig anwenden
Genau das versuche ich ja auch, aber wenn ich aus meinem Sicherheitsverständnis heraus lieber eine
Variable mehr als nötig initialisiere, dann sollte diese Warnung nicht kommen. Z.B. setzte ich schonmal Result := False; o.ä. pro Forma im Funktionkopf, und kann dann sicher sein das später nichts crasht. Es könnten ja auch mal Fehler im Compiler auftauchen (womöglich sind aber jetzt schon fehler drin), wo dann uninitialisierte Variablen herumhängen würden, genau dem will ich vorbeugen. Das wird extrem schwierig zu finden, falls soetwas mal in Delphi 10.xx Yokohama auftritt. Generell habe ich auch alle Warnings und Hints an, und ich räume nachher auch immer auf. Es gibt übrigens auch immer Warnings/Hints in Drittkomponenten die man nicht so einfach los wird. Auch das wäre ein Grund das mal gezielt abschalten zu können, warum nicht genauso wie bei den Warnings ? Rollo |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:08 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz