Create <-> Exception?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
laz847
Beiträge: 114
Registriert: Mi 18. Jun 2014, 16:39

Create <-> Exception?

Beitrag von laz847 »

Hallo, kurze Frage,

Code: Alles auswählen

TCPx = class 
 
TCPxHnd := TCPx.Create; 
Erzeugt eine neue Instanz der Klasse, danach kommt dann try f/e und end.

Ist klar, aber kann es beim Create nicht auch schon zu Fehlern kommen?

Setzt man das dann in 2 Blöcke oder wie macht man das ?

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Create <-> Exception?

Beitrag von mse »

Konstruktoren werden innerhalb eines impliziten try except Blockes ausgeführt. Falls eine exception auftritt, wird destroy() aufgerufen. destroy() muss also auch mit nur teilweise initialisierten Instanzen klarkommen.

Code: Alles auswählen

 
 TCPxHnd := TCPx.Create;
 try
  ...
 finally
  TCPxHnd.free(); //oder destroy() weil TCPxHnd hier sicher nicht nil ist
 end;
 
sollte genügen um Speicherlecks zu verhindern.
Zuletzt geändert von mse am Fr 20. Jun 2014, 06:57, insgesamt 1-mal geändert.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2807
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Create <-> Exception?

Beitrag von m.fuchs »

Pack das Create doch in den Try-Block:

Code: Alles auswählen

var
  MyObject: TObject = nil;
begin
  try
    MyObject := TObject.Create;
    [...]
  finally
    FreeAndNil(MyObject);
  end;
end;
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Create <-> Exception?

Beitrag von mse »

m.fuchs hat geschrieben:Pack das Create doch in den Try-Block:
Das wäre dann doppelt gemoppelt. ;-)

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2807
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Create <-> Exception?

Beitrag von m.fuchs »

Warum?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Create <-> Exception?

Beitrag von mse »

Weil Konstruktoren innerhalb eines impliziten try except Blockes ausgeführt werden, siehe oben. Wenn du durch den code stepst siehst du es. Für Delphi ist es auch dokumentiert:
http://docwiki.embarcadero.com/RADStudio/XE5/en/Methods
If an exception is raised during the execution of a constructor that was invoked on a class reference, the Destroy destructor is automatically called to destroy the unfinished object.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2807
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Create <-> Exception?

Beitrag von m.fuchs »

Ja, aufgeräumt wird die Instanz schon. Aber die Exception wird ja trotzdem weitergereicht. Und dann ist das Create innerhalb des try-Blocks schon sinnvoll. Das .Free einmal unnötig aufgerufen wird, kann man vernachlässigen. Schließlich sollen Exceptions nicht im Sekundentakt vorkommen.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Create <-> Exception?

Beitrag von mse »

Das ergibt aber das Problem, dass destroy() zwei mal aufgerufen wird, einmal implizit bei create() und ein zweites mal explizit im finally Block. In der Regel gibt das ein unschönes SIGSEGV.
Edit: Durch nil Initialisierung und free() funktioniert es, da die Zuweisung zur Instanzvariable wegen der exception nicht mehr ausgeführt wird.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2807
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Create <-> Exception?

Beitrag von m.fuchs »

Ja, deswegen immer Objektvariablen mit nil initialisieren und brav FreeAndNil nutzen! :)
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Philos
Beiträge: 43
Registriert: Mo 3. Mär 2014, 16:06
OS, Lazarus, FPC: Ubuntu Linux 14.04, Windows 7/8, Lazarus 1.2.2, Delphi XE5
CPU-Target: amd64
Wohnort: Rostock
Kontaktdaten:

Re: Create <-> Exception?

Beitrag von Philos »

Das Create in den try-Block zu packen geht aber auch nur mit FreeAndNil. Wenn man nur ein .Free benutzt, hat das Create im Try-Block nichts zu suchen.
((2*b) || !(to_be)) ... that's the question.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2807
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Create <-> Exception?

Beitrag von m.fuchs »

Und wieder frage ich: warum?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Philos
Beiträge: 43
Registriert: Mo 3. Mär 2014, 16:06
OS, Lazarus, FPC: Ubuntu Linux 14.04, Windows 7/8, Lazarus 1.2.2, Delphi XE5
CPU-Target: amd64
Wohnort: Rostock
Kontaktdaten:

Re: Create <-> Exception?

Beitrag von Philos »

Mein Gedanke ist folgender: ( bitte um Berichtigung, falls ich mich da täuschen sollte ;) )

Wenn beim Create schon etwas schiefgeht, dann habe ich kein wirkliches Objekt erhalten an der Stelle oder nur irgendwas Undefiniertes, auf das ich zugreifen kann. Wenn wir dann bei einem Error gleich ins
Except oder Finally springen, versucht Free ETWAS zu löschen an der angeblichen Adresse von unserer Instanz, die ja nun aber alles mögliche sein kann (da wir ja annahmen, dass Create nicht geklappt hat ). Ich könnte mir vorstellen, dass dies einige ungewünschte Effekte haben könnte.
((2*b) || !(to_be)) ... that's the question.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Create <-> Exception?

Beitrag von mse »

Die Instanz-Variable wird nur nach erfolgreichem create() gesetzt. Problematisch sind Fälle wo die Instanz-Variable im code gesetzt wird, z.B. durch Application.CreateForm().

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2807
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Create <-> Exception?

Beitrag von m.fuchs »

FreeAndNil ruft ja intern auch nur Free auf. Und das wiederum prüft vorher, ob Self auf nil zeigt (http://www.freepascal.org/docs-html/rtl ... .free.html). Von daher kein Problem.

FreeAndNil hat eben nur den Vorteil, dass es die übergebene Referenzvariable auf nil zeigen lässt.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

laz847
Beiträge: 114
Registriert: Mi 18. Jun 2014, 16:39

Re: Create <-> Exception?

Beitrag von laz847 »

Genau den Gedanke hatte ich als ich die Frage stellte ;).
Philos hat geschrieben:Mein Gedanke ist folgender: ( bitte um Berichtigung, falls ich mich da täuschen sollte ;) )

Wenn beim Create schon etwas schiefgeht, dann habe ich kein wirkliches Objekt erhalten an der Stelle oder nur irgendwas Undefiniertes, auf das ich zugreifen kann. Wenn wir dann bei einem Error gleich ins
Except oder Finally springen, versucht Free ETWAS zu löschen an der angeblichen Adresse von unserer Instanz, die ja nun aber alles mögliche sein kann (da wir ja annahmen, dass Create nicht geklappt hat ). Ich könnte mir vorstellen, dass dies einige ungewünschte Effekte haben könnte.
Was ist wenn der Create fehlschlägt, deswegen die Frage ob man das dann sinnvollerweise in 2 Blöcke verschachtelt?

Übrigens:
obj := TObj.Create;
try
obj.DoSomething;
finally
obj.Free;
end;

Zuerst wird das Objekt erstellt – aber Achtung: dies darf nicht im try-Block geschehen! Tritt nämlich beim Erstellen des Objekts ein Fehler auf, wird das Objekt nicht erstellt und darf somit auch nicht freigegeben werden, was ansonsten im finally-Block geschehen würde. Da sich dieser Befehl aber außerhalb des try-Blocks befindet, wird der finally-Block bei einem Laufzeitfehler im Konstruktor nie ausgeführt.Dann wird im try-Block eine Methode des Objekts aufgerufen und am Ende wird es wieder freigegeben. Auch wenn die aufgerufene Methode fehlschlägt, wird das Objekt freigegeben.Im Allgemeinen ist es guter Programmierstil, nach einer Instanzierung von einem Objekt immer ein try…finally…end Konstrukt einzusetzen – egal wie fehlersicher die nachfolgenden Aufrufe sind.
http://www.delphi-treff.de/tipps-tricks ... -abfangen/

Wie ist es denn nun richtig???

Code: Alles auswählen

 obj := TObj.Create;
try
  obj.DoSomething;
finally
  obj.Free;
end; 

Code: Alles auswählen

 obj := TObj.Create;
try
  obj.DoSomething;
finally
  obj.FreeAndNil;
end; 

Code: Alles auswählen

 try
 obj := TObj.Create;
 try
   obj.DoSomething;
 finally
   obj.Free;
 end;
except
 // error log
end; 

Code: Alles auswählen

 obj := TObj.Create;
try
 try
   obj.DoSomething;
 finally
   obj.Free;
 end;
except
 // error log
end; 

Antworten