Create <-> Exception?

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

Re: Create <-> Exception?

Beitrag von laz847 »

Und noch eine Frage

Code: Alles auswählen

TCPxHnd.free(); //oder destroy() weil TCPxHnd hier sicher nicht nil ist
Ich habe doch einen destructor

Code: Alles auswählen

type
  { TCPx }
  TCPx = class..........
 
constructor TCPx.Create;
begin
  FClient := TLTCP.Create(nil);
end;
 
destructor TCPx.Destroy;
begin
 FClient.Free;
 inherited Destroy;
end; 
 
function MT4_IPC_Init(const _dbg:Boolean=False):LongInt; stdcall;
begin
 TCPxHnd := TCPx.Create;
 TCPxHnd.FLog := _dbg;
 exit(LongInt(TCPxHnd));
end;  
 
function MT4_IPC_Deinit(const _ipch:integer):boolean; stdcall;
begin
 TCPxHnd.Free;
 exit(true);
end;
Damit sollte doch "TCPxHnd.Free" ausreichen oder nicht???

Sorry falls ich blöde Fragen stelle, ich beschäftige mich nach Jahren mal wieder mit Pascal und seit ein paar Tagen mit Klassen usw... :D

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 »

Code: Alles auswählen

 
      procedure TObject.Free;
 
        begin
           // the call via self avoids a warning
           if self<>nil then
             self.destroy;
        end;
 
Direkter destroy() Aufruf ist schneller.

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 »

Also dieser Geschwindigkeitsvorteil ist ja nun wirklich marginal. Eine Prüfung auf nil kostet ja nun nicht so viel Zeit.
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 »

Also in meinem Fall sollte sich das nicht bemerkbar machen, die dll wird einmal geladen und bleibt dann geladen, und ob das Beenden dann 0.1 Sekunden schneller geht merkt keiner. Aber es mag Bereiche geben in denen das wichtig ist.

TCPxHnd.free(); // oder destroy() weil TCPxHnd hier sicher nicht nil ist

Ok verstehe, man macht also aber auch nichts falsch mit .Free, das wollte ich nur mal mit Sicherheit wissen. Überall steht .Free dauernd sagen einem aber immer wieder Leute nimm Destroy, am Ende machts das kein Unterschied.

Könnte mal bitte jemand die letzte Frage auf Seite 1 beantworten, offenbar gibts da ja auch keine klare Aussage zu???

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 »

laz847 hat geschrieben:Überall steht .Free dauernd sagen einem aber immer wieder Leute nimm Destroy, am Ende machts das kein Unterschied.
Also die Dokumentation von Freepascal ist da schon recht aussagekräftig:
Free will check the Self pointer and calls Destroy if it is different from Nil. This is a safer method than calling Destroy directly. If a reference to the object must be reset as well (a recommended technque), then the function FreeAndNil should be called.
laz847 hat geschrieben:Könnte mal bitte jemand die letzte Frage auf Seite 1 beantworten, offenbar gibts da ja auch keine klare Aussage zu???
Welche meinst du?
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 »

Aslso am Ende gewinnt FreeAndNil :D ?

http://www.lazarusforum.de/viewtopic.php?p=69954#p69954
Wie ist es denn nun richtig???
Seite 1 letzter Beitrag :oops:

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 »

Also richtig und falsch ist immer so eine Sache, wie du hier in der Diskussion gemerkt hast. Ich mache es im Allgemeinen so:

Code: Alles auswählen

var
  obj: TObject = nil;
begin
  try
    try
      obj := TObject.Create;
    except
      // error log
    end;
  finally
    FreeAndNil(obj);
  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 »

laz847 hat geschrieben:

Code: Alles auswählen

 
obj := TObj.Create;
try
  obj.DoSomething;
finally
  obj.Free;
end; 
Richtig und üblich. Von der Performance her besser:

Code: Alles auswählen

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

Code: Alles auswählen

 
obj := TObj.Create;
try
  obj.DoSomething;
finally
  obj.FreeAndNil;
end; 
Das kompiliert nicht. Du meintest wohl:

Code: Alles auswählen

 
obj := TObj.Create;
try
  obj.DoSomething;
finally
  FreeAndNil(obj);
end; 
Nicht falsch. FreeAndnil ist unnötig, da obj nicht mehr verwendet wird. Die Verwendung von FreeAndnil ist für viele Programmierer ein Hinweis dafür, dass die Instanzvariable weiter verwendet wird und hier irreführend. FreeAndNil kann gefährlich sein, wenn im Destruktor auf die Instanzvariable zugegriffen wird, da die dann bereits nil ist (FreeAndNil bedeutet eigentlich NilAndFree). Bei Formularen und globaler Instanzvariable kann das bei event handlern vorkommen, welche aus destroy() oder afterdestruction() heraus aufgerufen werden und wo sich der Programmierer im On* event dessen vielleicht nicht bewusst ist.

Code: Alles auswählen

 
try
 obj := TObj.Create;
 try
   obj.DoSomething;
 finally
   obj.Free;
 end;
except
 // error log
end; 
Nicht falsch, obj.Free könnte durch obj.Destroy ersetzt werden. Im except-Abschnitt darf nicht auf obj zugegriffen werden, da obj im Falle einer exception in Create undefiniert ist. Besser, da mit der Prüfung von obj auf nil die Herkunft der exception bestimmt werden kann:

Code: Alles auswählen

 
try
 obj:= nil;
 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; 
Nicht falsch, der except Abschnitt erfasst nur exceptions aus DoSomething() und Destroy(). Im except Abschnitt darf nicht auf obj zugegriffen werden. Besser:

Code: Alles auswählen

 
obj := TObj.Create;
try
 try
   obj.DoSomething;
 except
   // error log
 end;
finally
 obj.Free;
end;
 
obj.Free könnte wieder durch obj.Destroy ersetzt werden.

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 »

mse hat geschrieben:Nicht falsch. FreeAndnil ist unnötig, da obj nicht mehr verwendet wird. Die Verwendung von FreeAndnil ist für viele Programmierer ein Hinweis dafür, dass die Instanzvariable weiter verwendet wird und hier irreführend.
Diese "Irreführung" schadet aber auch nicht. Dafür gewöhnt man sich dadurch die konsequente Nutzung von FreeAndNil an. In Verbindung mit der grundsätzlichen Initialisierung der Variablen mit nil, ist das eine gute Sache.
mse hat geschrieben:FreeAndNil kann gefährlich sein, wenn im Destruktor auf die Instanzvariable zugegriffen wird, da die dann bereits nil ist (FreeAndNil bedeutet eigentlich NilAndFree).
Das soll man ja auch nicht machen. Das Objekt sollte eigentlich niemals etwas von Instanzvariablen wissen. Abgesehen von wirklichen Spezialfällen wie bei einer Singleton-Implementierung. Und da baut man das ganze dann so sicher wie möglich.
mse hat geschrieben:Bei Formularen und globaler Instanzvariable kann das bei event handlern vorkommen, welche aus destroy() oder afterdestruction() heraus aufgerufen werden und wo sich der Programmierer im On* event dessen vielleicht nicht bewusst ist.
Ist auch keine gute Idee, dafür gibt es ja Self.
mse hat geschrieben:

Code: Alles auswählen

try
  obj := TObj.Create;
  try
    obj.DoSomething;
  finally
    obj.Free;
  end;
except
 // error log
end; 
Nicht falsch, obj.Free könnte durch obj.Destroy ersetzt werden. Im except-Abschnitt darf nicht auf obj zugegriffen werden, da obj im Falle einer exception in Create undefiniert ist.
Viel schlimmer: Auch im Falle einer Exception in DoSOmething ist obj undefiniert. Da das finally immer vor dem except durchgeführt wird. Deshalb empfahl ich in meinem vorherigen Post auch eine andere Reihenfolge.
mse hat geschrieben:obj.Free könnte wieder durch obj.Destroy ersetzt werden.
Was hast du eigentlich immer mit dieser Ersetzung? Die Anwendung, die Performanceprobleme hat, weil Free und nicht Destroy benutzt wird, möchte ich erst einmal sehen. Und dann kann man ja immer noch optimieren.
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: Was hast du eigentlich immer mit dieser Ersetzung? Die Anwendung, die Performanceprobleme hat, weil Free und nicht Destroy benutzt wird, möchte ich erst einmal sehen. Und dann kann man ja immer noch optimieren.
Ich vermeide grundsätzlich überflüssigen code. Wobei bei free()/destroy() habe ich mich bis jetzt an die free-Konvention gehalten, nehme diese Diskussion aber zum Anlass, in Zukunft free() nur noch dort einzusetzen, wo es tatsächlich gebraucht wird. Überall free() war mir schon immer suspekt. :-)

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

Re: Create <-> Exception?

Beitrag von laz847 »

Ja danke und ich nehm für den .Free Reset- und für .Destroy den Powerknopf ab jetzt :D :D

Irgendwie ist ja fast alles richtig aber irgendwie doch wieder nicht, können wir das irgendwie mal in eine klare Aussage bringen, dachte nicht das dieses Thema so umstritten ist - da war meine Unsicherheit ja gar nicht so blöd, möchte nicht wissen wie viele da etwas falsche haben...
FreeAndNil kann gefährlich sein, wenn im Destruktor auf die Instanzvariable zugegriffen wird, da die dann bereits nil ist (FreeAndNil bedeutet eigentlich NilAndFree). Bei Formularen und globaler Instanzvariable kann das bei event handlern vorkommen, welche aus destroy() oder afterdestruction() heraus aufgerufen werden

Code: Alles auswählen

var
  obj: TObject = nil;
begin
  try
    try
      obj := TObject.Create;
      <<<<<<<<<<< obj.DoSomething; ???
    except
      // error log
    end;
  finally
    FreeAndNil(obj);
  end;
end;
Und wo ist hier dann das DoSomething bzw wie werden jetzt Fehler im DoSomething abgefangen :) ???

Kann man das so zusammenfassen

obj: TObject = nil; <<<<<<<< immer

"Bei Formularen und globaler Instanzvariable" <<<<<<<< .Free

"Wenn keine globalen Vars benutzt werden " <<<<<<<<< FreeAndNil

???

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 »

Ich denke man sollte sich beim Programmieren nicht auf Faustregeln verlassen.
laz847 hat geschrieben: Und wo ist hier dann das DoSomething bzw wie werden jetzt Fehler im DoSomething abgefangen :) ???
Verstehe die Frage nicht.
Kann man das so zusammenfassen

obj: TObject = nil; <<<<<<<< immer
Schadet nicht.
"Bei Formularen und globaler Instanzvariable" <<<<<<<< .Free
Ja. Es gibt aber auch Fälle wo hier FreeAndNil verwendet werden muss, z.B. wenn irgendwo der Lebenszustand des Formulares durch nil-Prüfung der Instanzvariable bestimmt wird. MSEgui hat für den Zweck die "setlinkedvar()" Funktionen welche die nil-Setzung der Verweise beim destroy() automatisch erledigen.
"Wenn keine globalen Vars benutzt werden " <<<<<<<<< FreeAndNil
Schadet nicht.

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 »

Faustregeln müssen programmweit befolgt werden, damit sie funktionieren.

Dann würde ich folgende Regeln nutzen:
  • Objektvariablen immer mit nil initialisieren.
  • Immer FreeAndNil benutzen.
  • Immer mit Assigned prüfen, ob die Variable nicht nil ist.
  • Keine globalen Variablen benutzen bzw. so wenig wie möglich.
Und selbst dann, kannst du immer noch Probleme bekommen. Mit Faustregeln kannst du wirklich nicht alles abdecken. Aber wenn du dich so detailliert mit der Thematik beschäftigst, findest du mögliche Probleme schneller.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Antworten