![]() |
Frage zu Try..Finally/Except
hoi, ich hab ne frage, und zwar:
Delphi-Quellcode:
procedure bla;
var i: integer; sl: TStringList; begin sl := TStringList.Create; with sl do begin add('A'); add('B'); add('C'); end; for i := 0 to 3 do begin Try Try idHTTP1.Post('www.bla.de', sl); except ShowMessage('Can''t connect.'); end; finally //jo hier brauch ich garnix O_o end; end; sl.free <<<< wie soll ich die free'en, das finally gilt ja nur innerhalb des innersten blocks? end; |
Re: Frage zu Try..Finally/Except
Delphi-Quellcode:
Nur richtig schachteln.
procedure bla;
var i: integer; sl: TStringList; begin sl := TStringList.Create; try ------------------------------ with sl do | begin | ...; | end; | for i := 0 to do | begin | try ----------------------- | idHTTP:Post(...); | | except -------------------- | ShowMessage('Kuckuck'); | | end; ---------------------- | end; | finally -------------------------- sl.Free; | end; ----------------------------- end; |
Re: Frage zu Try..Finally/Except
Hi,
mal als grundsätzliche Regel folgendes beherzigen
Delphi-Quellcode:
var meineObjektVariable:TTypMeineObjektVariable;
begin try meineObjektVariable := TTypMeinerObjektVariablen.Create; try TuWas; finally meineObjektVariable.Free; end; except AusnahmeBehandeln; end; end; |
Re: Frage zu Try..Finally/Except
Zitat:
Delphi-Quellcode:
und zu
var
meineObjektVariable:TTypMeineObjektVariable; begin meineObjektVariable := TTypMeinerObjektVariablen.Create; try try TuWas; except AusnahmeBehandeln; end; finally meineObjektVariable.Free; end; end;
Delphi-Quellcode:
(vorausgesetzt, im Destruktor wird keine Exception geworfen).
var
meineObjektVariable:TTypMeineObjektVariable; begin meineObjektVariable := TTypMeinerObjektVariablen.Create; try TuWas; except meineObjektVariable.Free; AusnahmeBehandeln; end; end; Warum sollte man das grundsätzlich so machen, wie Du gezeigt hast? |
Re: Frage zu Try..Finally/Except
nein ist es nicht,
gib deinen code in delphi rein und kompiliere es du wirst Hints bekommen mit meiner version nicht und die zweite version von dir ist was völlig anderes da es im except freigegeben wird und wenn es keine except gibt, ist das objekt nicht freigegeben |
Re: Frage zu Try..Finally/Except
Zitat:
innerhalb eines try.... finally ..end; blockes kann man natürlcih so viel try ...except .. end; blöcke benutzen wie man möchte, aber bei jeder Objekterstellung sollte man vorgehen wie ich es beschrieben habe. mfg Tyrael |
Re: Frage zu Try..Finally/Except
Du hast Recht, in der dritten Version wird Free nur im Fall einer Exception aufgerufen, mein Fehler.
Ich konnte die Compilerhinweise leider nicht rekonstruieren: Weder in "Deiner" noch in "meiner" Version treten bei mir Meldungen auf (Ja, die Hints sind aktiviert). Marcelo beschreibt in seinem BDN-Artikel ![]() Es ist zu erkennen, das Verschachtelungen in beiden Ausprägungen nicht nur zulässig sondern in einigen Fällen auch zu "eleganterem" Code führen können. Es gibt demnach nicht nur "ein einzig richtiges Vorgehen",beim Erzeugen und Freibegen von Objekten. Oder vestehe ich hier etwas falsch? |
Re: Frage zu Try..Finally/Except
hi,
diese Version von dir ist nicht "vollkommen" falsch.
Delphi-Quellcode:
aber was ist wenn
var
meineObjektVariable:TTypMeineObjektVariable; begin meineObjektVariable := TTypMeinerObjektVariablen.Create; try try TuWas; except AusnahmeBehandeln; end; finally meineObjektVariable.Free; end; end;
Delphi-Quellcode:
NICHT geklappt hat??
meineObjektVariable := TTypMeinerObjektVariablen.Create;
Dann entsteht bei dir ne Ausnahme. Also benutz es lieber wie ich es beschrieben habe. Dann kann nix schiefgehen ;) mfg Tyrael |
Re: Frage zu Try..Finally/Except
ich muss dir widersprechen, sry
Zitat:
also nochmal
Delphi-Quellcode:
alles andere ist auch gut und schön, aber nicht 100% wasserdichttry Objekt erzeugen try ..... Hier darf alles stehen z.B auch andere try finally und try except blöcke ..... finally Objekt freigeben end; except Ausnahme bei Objekterzeugung behandeln end; NUR diese Version ist richtig. Wer was anderes behauptet, sollte noch bissel programmieren und wird bald,wenn er mal was komplexeres macht, nebeneffekte haben, die er lange suchen kann. mfg Tyrael |
Re: Frage zu Try..Finally/Except
Zunächst, Dein erstes Posting: Wenn der Aufruf von TTypMeinerObjektVariablen.Create; fehlschlägt, wird implizit der Destruktor für dieses Exemplar aufgerufen.
Der Code
Delphi-Quellcode:
kann daher bei lokalen Variablen zu fehlern führen, weil myVar bei einer Exception im Konstruktor nie beschrieben wird und die Nachricht Free deshalb an eine nicht-initialisierte Referenz geschickt (die Methode aufgerufen) wird.
try
myVar:= TMyClass.Create; finally myVar.Free; end; Reicht der implizite Aufruf des Destruktors nicht aus? Warum möchtest Du den Fall, dass der Constructor eine Exception wirft, abfangen? Wie willst Du reagieren, wenn der Destruktor, zB wg nur teilweise erzeugten aggregierten Objekten, seinerseits beim impliziten Aufruf eine Exception wirft? Mit dem Code
Delphi-Quellcode:
kannst Du diesen Fall gut simulieren und erkennen, dass die ursprüngliche Exception "verschluckt" wird.
type
TMyClass = class public constructor Create; destructor Destroy;override; end; constructor TMyClass.Create; begin inherited Create; raise Exception.Create('exception within a constructor'); end; destructor TMyClass.Destroy; begin raise Exception.Create('exception within a destructor'); inherited; end; procedure TForm1.Button1Click(Sender: TObject); var myVar: TMyClass; begin myVar:= TMyClass($badf00d); //stack contains rubbish try myVar:= TMyClass.Create; try finally myVar.Free; end; except on E:Exception do outputDebugString(PChar('Exception:'+E.Message)); end; end; Mit GetHeapStatus.TotalAllocated kannst Du Dich vergewissern, dass in diesem trivialen Bsp der gesamt Speicher durch den impliziten Aufruf freigegeben wird. Trotzdem: Durch ein simples Abfangen einer Exception, die vom Konstruktor geworfen wird, ist Dir bei aggregierten Objekten nicht geholfen, wenn der Destruktor mit einer Exception, die vom Konstruktor geworfen wird, nicht umgehen kann. |
Re: Frage zu Try..Finally/Except
Delphi-Quellcode:
ist doch völlig ok
type
TMyClass = class public constructor Create; destructor Destroy;override; end; constructor TMyClass.Create; begin inherited Create; raise Exception.Create('exception within a constructor'); end; destructor TMyClass.Destroy; begin raise Exception.Create('exception within a destructor'); inherited; end; procedure TForm1.Button1Click(Sender: TObject); var myVar: TMyClass; begin myVar:= TMyClass($badf00d); //stack contains rubbish try myVar:= TMyClass.Create; try finally myVar.Free; end; except on E:Exception do outputDebugString(PChar('Exception:'+E.Message)); end; end; hier rufts du alles auch richtig auf der destructor wird ja auch nur aufgerufen weil myVar.free auch durchgeführt wird es entsteht keine Exception
Delphi-Quellcode:
wird NUR aufgerufen wenn das Objeckt nicht erzeugt werden konnteexcept on E:Exception do outputDebugString(PChar('Exception:'+E.Message)); end; und das Objekt wird erzeugt der erste Wert für myChar wird ja auch überschrieben, deshalb ist alles ok mfg Tyrael |
Re: Frage zu Try..Finally/Except
Das Objekt wird nicht erzeugt, weil innerhalb des Konstruktors eine Exception geworfen wird und der vom Delphi-Compiler implizit generierte Code das Exemplar wieder freigibt (nachprüfbar im CPU-Fenster, mit einem geeigneten Profiler oder mithilfe von GetHeapStatus.TotalAllocated).
Bitte vergewissere Dich, dass der Destruktor implizit aufgerufen wird, indem Du die Zeile myVar.Free auskommentierst:
Delphi-Quellcode:
Und dann sieh Dir die Ausgabe von OutputDebugstring an. Notfalls solltest Du weitere Aufrufe dieser Prozedur in den Konstruktor/Destruktor einfügen, um den Programmverlauf nachzuverfolgen.
myVar:= TMyClass.Create;
try finally // myVar.Free; end; Noch einmal: Der Except-Abschnitt fängt nicht die Exception des Konstruktors ab, diese wird durch die Exception des Destruktors "verschluckt". Deshalb und auch, weil die Ressourcen im trivialen Fall ohnehin freigegeben werden, verstehe ich nicht, warum Du den Except-Block benötigst? Welchen Vorteil hat man hierdurch? |
Re: Frage zu Try..Finally/Except
Zitat:
Delphi-Quellcode:
wegen der nicht-vorinitialisierten Werte auf dem Stack zu problemen führen kann (siehe Kommentare).
myVar:= TMyClass($badf00d); //stack contains rubbish
try //myVar won't be altered since Create raises an exception myVar:= TMyClass.Create; finally //eq to TMyClass($badf00d).Free ->AccessViolation myVar.Free; end; |
Re: Frage zu Try..Finally/Except
Ja du hast vollkommen Recht, wenn beim kreieren des Objektes eine Ausnahme auftritt
und das Objekt nicht erstellt werden konnte, wird der Destructor aufgerufen(mini "garbage collector"). Du bräuchtest dich prinzipiell darum nicht mehr zu kümmern, aber... ...direkt nach dem Destructor Aufruf wird der Except Block aufgerufen.... ...es wird also eine Ausnahme erzeugt... ...in diesem könntest du jetzt auf das schiefgegangene Kreieren reagieren und je nach dem vielleicht einen DebugLogger einsetzten oder irgend ne andere Prozedur/Funktion aufrufen in der du alles wieder glattbügelst... ..oder einfach nix im Äußeren except Block schreibst... ..dann wird keine Ausnahme geworfen und du hast keine "lästige" Exception Anzeige... Wie gesagt es geht auch ohne das Äußere try except , aber wenn du 100%-ige Version haben möchtest kann ich das try except drumherum nur empfehlen. Hilft ungemein bei grossen Projekten, wenn du Fehler suchst, weil dann kannst du dir u.U. die suche sparen, z.B. wenn du einen DebugLog mitlaufen läßt. Ich würde mir angewöhnen diesen Äußeren try except Block IMMER zu schreiben. Ich habs mir angewöhnt, und es hilft wirklcih bei der Fehlersuche. mfg Tyrael |
Re: Frage zu Try..Finally/Except
Zitat:
Sicherlich, das ist eine funktionierende Lösung. Ich persönlich empfinde Exceptions weder als lästig noch als überflüssig. Stattdessen sind sie oft sinnvolle Helfer für außergewöhliche Situationen. Jedoch kann und sollte nicht jede Zeile Code mit jeder Ausnahmebedingung umgehen, deshalb "übersetze" ich Exceptions lieber und reiche sie bis zu jemanden durch (ExceptionChaining, ExceptionWrapping), der sie schließlich sinnvoll verarbeitet (zB der zuständige Broker des Frameworks oder der zuständige Kontext). Hier kann zur detaillierten Beschreibung durch die kumulierte Information genaue Ursache und Position der ersten Exception (hier: Konstruktur der Klasse TMyClass) über die jeweiligen Ebenen des Aufrufs (sollte aus Foo erzeugt werden, die von Bar aufgerufen wurde, in Thread FooBar (es leben benannte Threads!)). Für diese und ähnliche Aufgaben gibt es für Delphi gute Lösungen! Interessant ist vielleicht der Link aus ![]() |
Re: Frage zu Try..Finally/Except
danke luckie ^^ und danke an die anderen, beim grossen talk :-D
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:42 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