AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Tutorials [Tutorial] Den Destruktor verstehen
Tutorial durchsuchen
Ansicht
Themen-Optionen

[Tutorial] Den Destruktor verstehen

Ein Tutorial von sx2008 · begonnen am 15. Apr 2012 · letzter Beitrag vom 20. Apr 2012
 
Benutzerbild von sx2008
sx2008

Registriert seit: 15. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#1

[Tutorial] Den Destruktor verstehen

  Alt 15. Apr 2012, 05:20
Wenn in Delphi ein Objekt aus dem Leben scheidet dann gibt es nur einen einzigen Weg dies zu tun -
über den Destruktor.

Borland hat den Destruktor schon in der Vaterklasse TObject deklariert
Delphi-Quellcode:
TObject = class
...
public
...
  destructor Destroy; virtual;
end;
Zu jeder Klasse gibt eine VMT (virtual Method Table) und die Destroy-Methode hat dort einen festen Eintrag.
Der Index innerhalb der VMT ist mit der Konstanten vmtDestroy=-4 festgelegt.

Es gibt nur einen einzigen Destruktor.
Daraus kann man die Nebenbedingungen schlussfolgern
* der Destructor muss immer Destroy heisen
* der Destruktor kann keine Parameter haben und er hat auch keinen Rückgabewert
* der Destruktor muss immer mit override überschrieben werden
* der Destruktor darf keine eingeschränkte Sichtbarkeit haben; er ist also immer public

destructor Destroy; override; Jede Abweichung von dieser Deklaration ist falsch.

Hier ist ein Beispiel mit mehreren falsch deklarierten Destruktoren:
Delphi-Quellcode:
TMeineKlasse = class(TPersistent)
private
  destructor Destroy; // Falsch - override fehlt, darf nicht private sein
public
  destructor Destroy; override; // Richtig

  destructor GibFrei; // Falscher Name

  destructor Destroy; reindroduce; // Falsch da so die VMT ignoriert wird
end;
Warum hat der Destruktor überhaupt einen Namen, wenn es sowieso nur einen einzigen gibt?
Hätte der Destruktor keinen Namen, gäbe es keine Möglichkeit, ihn direkt aufrufen

Warum ist der Destruktor mit der Sichtbarkeit public deklariert, hätte man ihn nicht auch protected machen können?
Borland wollte offensichtlich dem Programmierer die Möglichkeit geben, den Destruktor direkt aufzurufen.

Warum gibt es eigentlich nur einen einzigen Destruktor?
Wenn ein Objekt freigeben wird, dann wird es nicht mehr gebraucht.
Derjenige, der das Objekt freigibt hat oftmals kein Wissen um was für ein Objekt es sich handelt.
Genauer gesagt, der Code, der ein Objekt freigibt soll gar keine näheren Infos zu Internas des Objekt haben. (Geheimnisprinzip des OOP)
Der Besitzer des Objekts sagt "Stirb!" und das Objekt hat zu gehorchen.

Was ist der Unterschied zwischen Free und Destroy?
Free ruft Destroy auf, abr nur wenn das Objekt überhaupt existiert; also der self-Pointer nicht nil ist.
Am Besten sieht man das, wenn man sich die Free-Prozedur anschaut.
Delphi-Quellcode:
procedure TObject.Free;
begin
  if Assigned(self) then Destroy;
end;
Darf man Destroy überhaupt aufrufen? Es heisst doch immer man solle Free verwenden.
Ja, man darf Destroy direkt aufrufen und man kann so einige CPU-Takte sparen.
Aber man darf dies nur tun, wenn man 1000% sicher ist dass man das Objekt selbst erzeugt hat:
Delphi-Quellcode:
var
  meinobj : TMeineKlasse;
begin
  meinobj := TMeineKlasse.Create;
  try
    meinobj.Machwas;
    meinobj.MasWasAnderes(42);
  finally
    // ja, das ist erlaubt aber nicht empfehlenswert
    // man spart hier die Überprüfung ob meinobj <> nil ist
    // aber es besteht die Gefahr, dass der Code mal verändert wird
    // und dann die Änderung von Destroy nach Free vergessen wird
    meinobj.Destroy;
  end;
end;
Welcher Code gehört in einen Destruktor?
Auf jeden Fall sollte der Aufruf von Inherited die letzte Zeile im Destruktor sein.
Delphi-Quellcode:
destructor TMeinKlasse.Destroy;
begin
  FList.Free;
  inherited;
end;
Man sollte im Destruktor nur belegte Resourcen (also eingebette Objekte, Window-Handles) freigeben.
Grössere Aktionen wie z.B. Speichern in einer Datenbank sollten vermieden werden.

Soll ich einen Destruktor auch dann verwenden, wenn gar nicht zu tun ist?
Nein, ein Destruktor sollte man nur dann deklarieren, wenn auch etwas zu tun ist.
Delphi-Quellcode:
// schlechter Stil: unnötiger Code und unnötiger Eintrag in der VMT
destructor TMeineKlasse.Destroy;
begin
  inherited;
end;
Wenn ich direkt von TObject ableite, dann brauche ich doch das inherited im Destruktor gar nicht aufrufen, oder?
Das ist im Prinzip richtig, aber man sollte als Programmierer nicht versuchen übertrieben clever zu sein.
Niemand weiss nicht ob nicht jemand in Zukunft die Klasse von einer anderen Basisklasse ableitet
und dann entsteht ein Resourcen-/Speicherleck.

Was sind die häufigsten Fehler beim Destruktor?
Das override bei der Deklaration zu vergessen oder das inherited innerhalb des Destruktor zu vergessen sind die Klassiker.

Warum braucht man überhaupt das inherited im Destruktor? Könnte Delphi das nicht automatisch aufrufen?
Gute Frage! In anderen Programmiersprachen (z.B. C++, C#) ist es tatsächlich so,
dass automatisch die ererbten Destruktoren aufgerufen werden, ohne dass sich der Programmierer darum kümmern müsste.
  Mit Zitat antworten Zitat
 


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:51 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz