Autor Beitrag
freedy
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 403
Erhaltene Danke: 1

Winows 7
Delphi XE
BeitragVerfasst: Mi 30.09.09 14:43 
Hallo Forum,

kennt ihr eine Möglichkeit den Konstruktor zu unterbrechen und eine Instanz nicht anzulegen, wenn beim Anlegen ein Fehler aufgetreten ist?

Ich habe probiert mit Raise eine Exception aufzurufen. Das gibt aber am Programmende nur Probleme mit nicht freigegebenen Speicher.

Ein Beispiel für diesen Bedarf ist z. B. folgendes: der Konstruktor erwartet ein Owner-Objekt. Wenn dieses aber nil ist, soll die Instanz der Klasse nicht angelegt werden. Bisher habe ich mich noch nicht getraut, innerhalb des Konstruktors ein Free aufzurufen, weil ich denke, dass das ein totales Chaos gibt.

Habt ihr einen Rat?

Grüße,
Micha
Tastaro
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 414
Erhaltene Danke: 23



BeitragVerfasst: Mi 30.09.09 14:59 
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
type
   EEinFehler = class(exception)
   end;


   TKlasse = class(tobject)
   private
      FIrgendwas: TIrgendwas;
   public
      constructor create(EinObjekt: TEinObjekt);

      destructor Destroy;
                 override;
   end;



implementation


constructor TKlasse.create(EinObjekt: TEinObjekt);
begin
   inherited create;
   FIrgendwas := nil;
   if not assigned(EinObject) then
      raise EEinFehler.create('oO')
   else
      FIrgendwas := TIrgendwas.create;
end;

destructor TKlasse.destroy;
begin
   if assigned(FIrgendwas) then
      FIrgendwas.free;
   inherited destroy;
end;


Beste Grüße
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Mi 30.09.09 15:07 
Ich bin mir da nicht ganz sicher, aber das Free im Constructor scheint erlaubt zu sein.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
type TTest = class(TObject)
  constructor Create(f: Boolean);
end;

//...

Constructor tTest.Create(f: Boolean);
begin
  if not f then free;
end;

// ...

TTest.Create(false); // erzeugt weder Fehler zur Laufzeit noch Memoryleaks am Ende
TTest.Create(True); // erzeugt Memoryleak

_________________
We are, we were and will not be.
Tastaro
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 414
Erhaltene Danke: 23



BeitragVerfasst: Mi 30.09.09 15:23 
Wenn man den Konstruktor mit einer Exception abbricht gibt es meines Wissens und meiner Erfahrung nach kein Memoryleak.

Beste Grüße
freedy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 403
Erhaltene Danke: 1

Winows 7
Delphi XE
BeitragVerfasst: Mi 30.09.09 15:37 
user profile iconTastaro hat folgendes geschrieben Zum zitierten Posting springen:
Wenn man den Konstruktor mit einer Exception abbricht gibt es meines Wissens und meiner Erfahrung nach kein Memoryleak


Richtig. Habe ich nochmal mit einer Testklasse probiert. Dann muss mein Fehler irgendwo anders liegen. Jedenfalls bekomme ich bei Abbruch zwei Memoryleaks (1x String, 1x Exception).

Vielen Dank erstmal.
dummzeuch
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: Mi 30.09.09 21:25 
user profile iconfreedy hat folgendes geschrieben Zum zitierten Posting springen:

kennt ihr eine Möglichkeit den Konstruktor zu unterbrechen und eine Instanz nicht anzulegen, wenn beim Anlegen ein Fehler aufgetreten ist?

Ich habe probiert mit Raise eine Exception aufzurufen. Das gibt aber am Programmende nur Probleme mit nicht freigegebenen Speicher.


Wenn man im Konstruktor eine Exception ausloest, so wird automatisch der zugehoerige Destruktor aufgerufen. Dh. der Destruktor muss damit klarkommen, dass evtl. das Objekt nur teilweise erzeugt ist. Das ist in der Regel kein Problem, weil alle Felder mit 0 / NIL / Leerstring initialisiert werden, also folgendes einfach nur funktioniert:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
constructor TMyObject.Create;
begin
  inherited Create;
  raise Exception.Create('Test');
  FMyList := TList.Create;
end;

destructor TMyObject.Destroy;
begin
  FMyList.Free;
  inherited;
end;


Da FMyList mit NIL initialisiert wird, kann man im Destruktor einfach FMyList.Free (oder alternativ FreeAndNil(FMyList)) aufrufen, da die Methode Free ueberprueft, ob SELF <> NIL ist.

Der langen Rede kurzer Sinn: Exceptions sind durchaus dazu geeignet, die Erzeugung eines Objekts im Konstruktor zu verhindern. Bei korrekten Destruktoren sollte es dabei auch keine Speicherlecks geben.

twm
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Do 01.10.09 09:41 
Innerhalb des Konstruktors ist der Aufruf der Funktion Fail erlaubt. Dabei wird eine Exception ausgelöst, die bereits angelegte Instanz wieder freigegeben und die Kontrolle an den nächst-höheren Exception-Handler gegeben.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.