![]() |
Behandlung von Exceptions innerhalb von Konstruktoren
Hallo allerseits,
ich habe mir schon oft die Frage gestellt, wie man eigentlich korrekterweise mit Exceptions innerhalb von Konstruktoren selbstgeschriebener Klassen umgeht. Als Beispiel habe ich mal ein kleines Mini-Programm entworfen mit einer selbstdefinierten Klasse (von TObject abgeleitet) und einem eigenen Konstruktor, in der nichts weiter gemacht wird, als eine Exception ausgelöst. Aber schaut es euch selber an:
Delphi-Quellcode:
In der ButtonClick-Routine wird ein Objekt der Klasse TMyClass erzeugt, in deren Konstruktor bereits eine Exception auftritt.
type
TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; type TMyClass = class(TObject) private public constructor Create(bCreateException: Boolean); end; var Form1: TForm1; implementation {$R *.dfm} { TMyClass } constructor TMyClass.Create(bCreateException: Boolean); begin inherited Create; if bCreateException then raise Exception.Create('Test'); end; procedure TForm1.Button1Click(Sender: TObject); var MyObject : TMyClass; begin try MyObject := TMyClass.Create(True); except if Assigned(MyObject) then FreeAndNil(MyObject); end; end; Nun meine Frage: Wird durch das "inherited Create" innerhalb des Konstruktors bereits Speicher allokiert (ja oder?) und wie gebe ich den dann anschließend frei??? Die Funktion "Assigned(MyObject)" liefert True zurück, das FreeAnNil anschließend erzeugt jedoch eine Speicherzugriffsverletzung. Oder sind Exceptions innerhalb von Konstruktoren so ein typischen Unding, was man nie nie nie nie [...] nie nie niemals bei Delphi machen sollte :wink: ? Vielen Dank im Voraus für die Hilfe! |
Re: Behandlung von Exceptions innerhalb von Konstruktoren
Delphi packt ein try-except um die Konstruktoren, sodass bei einer Exception automatisch alles wieder freigegeben und destroy aufgerufen wird.
|
Re: Behandlung von Exceptions innerhalb von Konstruktoren
Zu dem Code noch zwei Anmerkungen:
Delphi-Quellcode:
1. Das If Assigned() kannst du dir sparen, das macht .Free intern selber (welches durch FreeAndNil() aufgerufen wird).
procedure TForm1.Button1Click(Sender: TObject);
var MyObject : TMyClass; begin try MyObject := TMyClass.Create(True); except if Assigned(MyObject) then FreeAndNil(MyObject); end; end; 2. Ohne Initialisierung der Variable auf nil, knallt es so oder so, da das eine lokale Variable ist welche nicht initialisiert ist und somit ist die Möglichkeit eines recht ungültigen Wertes hoch. Dagegen kann auch Assigned() nichts ausrichten, da es nur auf <> nil prüft... Und da du nicht freigeben brauchst, wie zuvor erklärt, kannst du dir somit gleich viel mehr sparen: Somit so:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var MyObject : TMyClass; begin try MyObject := TMyClass.Create(True); except ShowMessage('Problem beim anlegen der Instanz'); end; end; |
Re: Behandlung von Exceptions innerhalb von Konstruktoren
Um das mit den Konstruktoren nochmal klar zu stellen. IMHO ist es noch nicht ganz so klar beschieben:
- Create immer vor das try:
Delphi-Quellcode:
- Alternative: vorher nillen(insbesondere praktisch, wenn man mehrere Objekte hat):
var
test: TTest; begin test := TTest.Create; try try test.DoSth(...); except ShowMessage('Die Welt geht gleich unter...'); end; finally test.Free; // von mir aus auch FreeAndNil(), aber das ist hier nicht nötig, da die Variable beim Verlassen des Gültigkeitsbereiches ja eh im Nirwana verschwindet end; end;
Delphi-Quellcode:
- Wenn im Konstruktor eine Exception auftritt, kümmert sich Delphi darum, dass die schon reservierten ressourcen wieder freigegeben werden(siehe Muetzes Post)
var
test: TTest; begin test := nil; try try test := TTest.Create; test.DoSth(...); except ShowMessage('Die Welt geht gleich unter...'); end; finally test.Free; // von mir aus auch FreeAndNil(), aber das ist hier nicht nötig, da die Variable beim Verlassen des Gültigkeitsbereiches ja eh im Nirwana verschwindet end; - Will man auf eine im Konstruktor geworfene Exception reagieren, so nimmt man am besten die 2. oben genannte Variante. - Alternativ kann man auch einen weiteren try...except Block ganz außen drum herum bauen, muss aber dann drauf achten, dass man dort auf das Objekt nicht mehr zugreifen kann... mfg Christian |
Re: Behandlung von Exceptions innerhalb von Konstruktoren
oder so:
Delphi-Quellcode:
var
test: TTest; begin try test := TTest.Create(); try //do anything with the objectinstance of test except ShowMessage('Fehler beim hantieren mit dem Object.'); end; test.Free; except ShowMessage('Fehler beim erzeugen des Objectes.'); end; |
Re: Behandlung von Exceptions innerhalb von Konstruktoren
Die letzte Meldung sollte wohl eher heissen: "Fehler beim Erzeugen oder Freigeben des Objectes."
|
Re: Behandlung von Exceptions innerhalb von Konstruktoren
OK, ich verstehe, erstmal danke für ausführliche die Hilfe :o !
Wäre denn auch folgender Aufbau sinnvoll (so würde ich es dann machen wollen):
Delphi-Quellcode:
procedure TForm1.TuWas;
var Test: TTest; begin try Test := TTest.Create(); try // Irgendwas mit Test anstellen finally FreeAndNil(Test); // habe mir eben FreeAndNil angewöhnt ;) end; except ShowMessage('Es trat in Prozedur "TuWas" ein Fehler auf.'); end; end; |
Re: Behandlung von Exceptions innerhalb von Konstruktoren
Jo, is IMHO OK so...
mfg Christian |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:18 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