Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Frage zu Try..Finally/Except (https://www.delphipraxis.net/11255-frage-zu-try-finally-except.html)

Pseudemys Nelsoni 3. Nov 2003 03:52


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;

Luckie 3. Nov 2003 05:35

Re: Frage zu Try..Finally/Except
 
Delphi-Quellcode:
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;
Nur richtig schachteln.

Tyrael Y. 3. Nov 2003 12:58

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;

choose 3. Nov 2003 13:10

Re: Frage zu Try..Finally/Except
 
Zitat:

Zitat von Tyrael Y.
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;

Dein Code ist Äquivalent zu
Delphi-Quellcode:
var
  meineObjektVariable:TTypMeineObjektVariable;
begin
  meineObjektVariable := TTypMeinerObjektVariablen.Create;
  try
    try
      TuWas;
    except
      AusnahmeBehandeln;
    end;
  finally
    meineObjektVariable.Free;
  end;
end;
und zu
Delphi-Quellcode:
var
  meineObjektVariable:TTypMeineObjektVariable;
begin
  meineObjektVariable := TTypMeinerObjektVariablen.Create;
  try
    TuWas;
  except
    meineObjektVariable.Free;
    AusnahmeBehandeln;
  end;
end;
(vorausgesetzt, im Destruktor wird keine Exception geworfen).

Warum sollte man das grundsätzlich so machen, wie Du gezeigt hast?

Tyrael Y. 3. Nov 2003 13:11

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

Tyrael Y. 3. Nov 2003 13:15

Re: Frage zu Try..Finally/Except
 
Zitat:

Warum sollte man das grundsätzlich so machen, wie Du gezeigt hast?
weil es die einzig wirklich richtige version ist ;)


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

choose 3. Nov 2003 13:47

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 Exceptional exceptions, Learn about structured exceptions and some unusual ways to use them nicht nur das Verfahren, auf das ich mich berufe sondern zeigt ebenfalls die Besonderheiten der Methode Free auf.

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?

Tyrael Y. 3. Nov 2003 14:32

Re: Frage zu Try..Finally/Except
 
hi,

diese Version von dir ist nicht "vollkommen" falsch.

Delphi-Quellcode:
var
  meineObjektVariable:TTypMeineObjektVariable;
begin
  meineObjektVariable := TTypMeinerObjektVariablen.Create;
  try
    try
      TuWas;
    except
      AusnahmeBehandeln;
    end;
  finally
    meineObjektVariable.Free;
  end;
end;
aber was ist wenn
Delphi-Quellcode:
meineObjektVariable := TTypMeinerObjektVariablen.Create;
NICHT geklappt hat??
Dann entsteht bei dir ne Ausnahme.

Also benutz es lieber wie ich es beschrieben habe.
Dann kann nix schiefgehen ;)


mfg

Tyrael

Tyrael Y. 3. Nov 2003 14:43

Re: Frage zu Try..Finally/Except
 
ich muss dir widersprechen, sry


Zitat:

Es gibt demnach nicht nur "ein einzig richtiges Vorgehen",beim Erzeugen und Freibegen von Objekten.
es gibt nur EINE vernünftige Version,wenn du alles beachten möchtest


also nochmal

Delphi-Quellcode:

 try
   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;
alles andere ist auch gut und schön, aber nicht 100% wasserdicht


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

choose 3. Nov 2003 15:01

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:
try
  myVar:= TMyClass.Create;
finally
  myVar.Free;
end;
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.

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:
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;
kannst Du diesen Fall gut simulieren und erkennen, dass die ursprüngliche Exception "verschluckt" wird.

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.

Tyrael Y. 3. Nov 2003 15:21

Re: Frage zu Try..Finally/Except
 
Delphi-Quellcode:
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;
ist doch völlig ok
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:

  except
    on E:Exception do
      outputDebugString(PChar('Exception:'+E.Message));
  end;
wird NUR aufgerufen wenn das Objeckt nicht erzeugt werden konnte
und das Objekt wird erzeugt

der erste Wert für myChar
wird ja auch überschrieben, deshalb ist alles ok

mfg
Tyrael

choose 3. Nov 2003 15:48

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:
myVar:= TMyClass.Create;
try
finally
//  myVar.Free;
end;
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.

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?

choose 3. Nov 2003 15:52

Re: Frage zu Try..Finally/Except
 
Zitat:

Zitat von Tyrael Y.
der erste Wert für myChar
wird ja auch überschrieben, deshalb ist alles ok

Der ungültige Wert sollte beim debuggen helfen und demonstrieren, dass der Code
Delphi-Quellcode:
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;
wegen der nicht-vorinitialisierten Werte auf dem Stack zu problemen führen kann (siehe Kommentare).

Tyrael Y. 3. Nov 2003 16:14

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

choose 4. Nov 2003 17:06

Re: Frage zu Try..Finally/Except
 
Zitat:

ich hoffe jetzt ist deutlich geowrden, warum ich bei einen Objekterzeugung
ein try except drumherum setze.

meistens logge ich im try except teil die Exception in eine Datei
und kann dann später gucken was alles schief gelaufen ist.

es ist nicht zwingend notwendig, aber hilft ungemein bei der Fehlersuche


mfg

Tyrael
Danke für Deine PN, Tyrael.
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 diesem Posting oder das J2EE-Exception-Handling-Konzept iA.

Pseudemys Nelsoni 5. Nov 2003 02:37

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