Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Problem beim zerstören von Instanz (https://www.delphipraxis.net/37327-problem-beim-zerstoeren-von-instanz.html)

stoermi 4. Jan 2005 15:25


Problem beim zerstören von Instanz
 
Hallo!
Ich hab ein Problem beim zerstören von Instanzen beim Beenden des Programms!
Und zwar habe ich eine Reihe von Instanzen einer Klasse x. In dieser Klasse x befindet sich eine Variable, die auf eine Instanz der Klasse y zeigt.
Am Ende des Programms durchlaufe ich alle Instanzen der Klasse x und schaue mittels assigned, bevor ich sie zerstöre, ob in der Variable noch eine Instanz der Klasse y besteht.
Bringt mir das true, wird auch die Instanz von y zerstört.
Doch jetzt zum Problem: Wenn ich zur Laufzeit bereits durch eine andere Methode die Instanz von y zerstört habe, liefert mir assigned trotzdem true und wenn ich dann die Instanz zerstören will, kommt es zur Exception: der Klasse EConvertError Format '%p' ungültig oder nicht kompatibel mit Argument.
Woran könnte das liegen?

Das wird durchlaufen:
Delphi-Quellcode:
  for i := length(zimmerObj)-1 downto 0 do
  begin
    if assigned(zimmerObj[i].buchung) then
    begin
      if assigned(zimmerObj[i].buchung.kunde) then
      begin
        zimmerObj[i].buchung.kunde.Free;
      end;
      zimmerObj[i].buchung.Free;   //Hier nach kommt der Fehler
    end;
    zimmerObj[i].Free;
  end;
Damit zerstöre ich es während der Laufzeit in einem anderen Formular:
Delphi-Quellcode:
    myZimmer.buchung.kunde.Free;
    myZimmer.buchung.Free;

Christian Seehase 4. Jan 2005 15:29

Re: Problem beim zerstören von Instanz
 
Moin Stoermi,

da Du in dem Falle wohl nicht FreeAndNil verwenden kannst, sollest Du nach dem .Free noch ein := nil hinzufügen.
Dann klappt auch Assigned.

bttb930 4. Jan 2005 16:33

Re: Problem beim zerstören von Instanz
 
Man muß beim Anwenden von Free gar nicht nachfragen ob die Variable zugewiesen ist oder nicht. Folgendes führt zu keinem Fehler:

Delphi-Quellcode:
  sl := TStringList.Create;
  sl.Free; // gibt die StringList frei. sl ist hinterher NICHT nil, sondern zeigt ins leere
  sl.Free; // funktioniert trotzdem!
Das liegt daran, dass Free eine Klassenfunktion ist. Bei Dir tritt ein Fehler auf, weil Du

Delphi-Quellcode:
  buchung.kunde.Free;
aufrufst - das funktioniert nur wenn buchung nicht ins Leere zeigt und nicht nil ist. (Der Fehler ist also nicht das Free, sondern das buchung.kunde - buchung zeigt ins nirvana und kunde ist dort nicht zu finden)

Immer beachten:
Ein Zeiger / eine Klasse die man noch braucht sollte man nach dem Aufruf von Free immer auf nil setzen, damit man an anderer Stelle weiß ob sie auf einen Wert zeigt oder nicht. Das kann man entweder mit zwei Befehlen machen (sl.Free; sl := nil;) oder mit FreeAndNil(sl).

Frage: Warum programmierst Du nicht objektorientiert und gibst den Kunden im Destruktor der Buchung automatisch frei? Dann reiche Buchung.Free; und den ganzen anderen Kram kannst Du dir schenken.

Christian Seehase 4. Jan 2005 17:24

Re: Problem beim zerstören von Instanz
 
Moin bttb930,

Zitat:

Zitat von bttb930
Man muß beim Anwenden von Free gar nicht nachfragen ob die Variable zugewiesen ist oder nicht. Folgendes führt zu keinem Fehler:

Delphi-Quellcode:
  sl := TStringList.Create;
  sl.Free; // gibt die StringList frei. sl ist hinterher NICHT nil, sondern zeigt ins leere
  sl.Free; // funktioniert trotzdem!
Das liegt daran, dass Free eine Klassenfunktion ist.

Free ist keine Klassenfunktion.
Es liegt daran, dass zwischen den Zugriffen der Speicher noch nicht anderweitig verwendet wurde, und somit noch das Objekt enthält.
Das Ganze kann nämlich auch ebensogut auf einen Fehler auflaufen.

bttb930 10. Jan 2005 14:15

Re: Problem beim zerstören von Instanz
 
Stimmt, Free ist tatsächlich keine Klassenfunktion.

Free ist allerdings nicht virtuell, und DAS ist der Grund warum man statt
Delphi-Quellcode:
if self <> nil then
  self.Free;
auch einfach
Delphi-Quellcode:
self.Free;
aufrufen kann, denn selbst wenn self = nil ist, findet der Compiler die Funktion Free, da sie nicht virtuell gelinkt wird, sondern statisch. Und Free prüft als erstes ob self = nil ist oder nicht.

Das Beispiel das ich oben geschrieben habe funktioniert (wie Christian schreibt) tatsächlich nur dann, wenn der Speicher noch nicht anderweitig überschrieben wurde, was einfach daran liegt dass nach dem ersten Free sl <> nil ist. Funktioniert also i.d.R. nicht, da davon ausgegangen werden muß, dass der Speicher in der Zwischenzeit überschrieben wurde.

Danke für die Korrektur, Christian, sonst hätte ich meine fehlerhafte Theorie im Kopf behalten.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:49 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