AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi Destroy wird ohne Aufruf ausgeführt - total strange...
Thema durchsuchen
Ansicht
Themen-Optionen

Destroy wird ohne Aufruf ausgeführt - total strange...

Ein Thema von s.h.a.r.k · begonnen am 14. Aug 2008 · letzter Beitrag vom 14. Aug 2008
Antwort Antwort
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#1

Destroy wird ohne Aufruf ausgeführt - total strange...

  Alt 14. Aug 2008, 08:44
Guten Morgen,

ich habe seit gestern Abend das seltsame Problem, dass der Destructor Destroy() einer Klasse ausgeführt wird, ohne ihn aber gerufen zu haben, auch nicht mit FreeAndNil() oder dergleichen. Anschließend landet meine Anwendung in einer Endlosschleife und meldet eine Exception "Stack-Überlauf".

Ich habe das folgende Konstrukt: ich lade aus der Datenbank Datensätze und erzeuge daraus ein paar Daten-Objekte, welche ich in einer TList "speichere". Ich kann dann jeweils eine Form zu einer dieser Objekte erzeugen, über welche ich dann die Werte bearbeiten kann. Der Form übergebe ich eben eine Referenz.

Nun habe ich parallel dazu einen Timer-Manager geschrieben, welcher in regelmäßigen Abständen Werte in der Datenbank ändert. Wird nun eine Form zu einem Datensatz geöffnet registriere ich das Daten-Objekt beim Timer-Manager, was ich so realisiert habe, dass ein passendes Objekt erzeugt wird, welches als Referenz das Daten-Objekt erhält, um das neu erzeugte Objekt später wieder passend auffindbar zu machen. Dieses neue Objekt schiebe ich dann in eine TList vom Timer-Manager.

Jetzt kommt das Problem und die Situation die ich nicht verstehe: wenn ich nun die Form schließe, dann teile ich dem Timer-Manager in der OnClose()-Methode mit, dass er doch bitte das Objekt in seiner TList, passend zum Daten-Objekt, freigeben soll. Ich suche mir das passende Objekt heraus, dann folgt ein TList.Delete() und anschließend ein FreeAndNil() auf dieses Objekt. Davon dürfte ja das Daten-Objekt nicht betroffen sein, allerdings wird genau da danach dann die Destroy()-Methode des Daten-Objekts aufgerufen und ich habe keine Ahnung wieso es kann ja wohl nicht an der Referenz liegen, da sonst sämtliche Datenstrukturen in meiner Anwendung Schrott wären und bisher hat es ja auch so funktioniert.

Vielleicht hilft es noch, wenn ich euch mitteile, dass die Klasse zum Datenobjekt und die Objekte im Timer-Manager vom selben Interface abgeleitet sind, was aber nicht das Problem sein darf, da dies ja nur eine Vorschrift für die Klasse ist, oder!? Ich weiß grad selbst nicht mehr recht ein und aus... das kann es echt nicht sein.

PS: ich würde ja gerne einen Quelltext exportieren, allerdings ist das Projekt sehr umfangreich und es würde zu lange dauern. Außer ich komme eben nie auf eine Lösung, dann muss ich das wohl tun.

Mit freundlichen Grüßen
Armin
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#2

Re: Destroy wird ohne Aufruf ausgeführt - total strange...

  Alt 14. Aug 2008, 09:02
Dass du nicht den Quelltext kopieren kannst, verstehe ich. Aber könntest du vielleicht eine UML-Skizze o.ä. anhängen? Ich komme bei der Klassenbeschreibung nicht ganz mit.


Edit 1:
(vielleicht habe ich es jetzt doch verstanden)

Du hast also in deinem Timer-Manager eine Liste welches u.a. ein Objekt1 enthält, indem ein Objekt2 enthalten ist (was dein Daten-Objekt ist). Nun willst du Objekt1 löschen aber Objekt2 behalten (weil woanders noch referenzen darauf sind). Und aus irgendwelchen Gründen löscht Objekt1, Objekt2 gleich mit.

Hmm? Von was sind sie den abgeleitet. Ich könnte mir jetzt z.B. TComponent o.ä. als Vorfahr vorstellen.


Edit2:
Kannst du nicht einen Breakpoint in den Destructor setzen und schauen wohin er zurückspringt?
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
xaromz

Registriert seit: 18. Mär 2005
1.682 Beiträge
 
Delphi 2006 Enterprise
 
#3

Re: Destroy wird ohne Aufruf ausgeführt - total strange...

  Alt 14. Aug 2008, 09:48
Hallo,

habe ich das richtig verstanden, dass Du Interfaces verwendest? Dann vermute ich, dass die automatische Referenzzählung zuschlägt.

Gruß
xaromz
I am a leaf on the wind - watch how I soar
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#4

Re: Destroy wird ohne Aufruf ausgeführt - total strange...

  Alt 14. Aug 2008, 10:44
Zitat von xaromz:
... Dann vermute ich, dass die automatische Referenzzählung zuschlägt.
Könntest du mir diesen Punkt näher erläutern? Denn das hört sich recht vielversprechend an! Ich leite eben von TInterfacedObject und einem eigenen Interface ab, sodass ich die drei Methode QueryInterface, _AddRef und _Release nicht selbst schreiben muss. Habe dazu im Internet nicht viel gefunden gehabt und daher wollte ich sie nicht selbst programmieren... vielleicht war das nicht ganz geschickt. Kann man diese Methoden eigentlich auch leer lassen, bzw was wären die Konsequenzen dies bzgl.? Kenne mich mit Interfaces nicht wirklich aus.

Zur Näheren Erklärung:
  • ObjectMananger beinhaltet Daten-Objekte
  • zu jedem Daten-Objekt kann eine Form erzeugt werden
  • wird eine Form erzeugt, so wird automatisch im Timer-Manager ein neues Objekt erzeugt mit einer Referenz auf das passende Daten-Objekt
  • wird die Form geschlossen soll das Object im Timer-Manager zerstört werden, aber nicht das Daten-Objekt

Würde es evtl. etwas bringen, wenn ich den Quellcode so lasse und zuvor die Referenz im Objekt des Timer-Managers auf nil setze?
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Benutzerbild von Flocke
Flocke

Registriert seit: 9. Jun 2005
Ort: Unna
1.172 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#5

Re: Destroy wird ohne Aufruf ausgeführt - total strange...

  Alt 14. Aug 2008, 11:02
TInterfacedObject ist für die Fälle gedacht, wo dein Objekt nach der Initialisierung nur noch über das Interface angesprochen wird, also z.B. ganz abstrakt:
Delphi-Quellcode:
type
  ISomeInterface = interface
  end;

  TSomeInterface = class(TInterfacedObject, ISomeInterface)
  end;

var
  i: ISomeInterface;

begin
  i := TSomeInterface.Create(...) as ISomeInterface;
end;
Ab der Zuweisung kannst du das Objekt (TSomeInterface) vergessen. Du musst es nicht mehr freigeben - das geschieht automatisch, wenn der Referenzzähler 0 erreicht. Delphi erhöht/vermindert diesen Referenzzähler automatisch bei der Übergabe von Parametern und bei der Zuweisung an Variablen, im Beispiel oben würdest du das Objekt also einfach durch:
  i := nil; wieder freigeben. Noch "automatischer" ist dies bei lokalen Variablen, für die Delphi automatisch einen try-finally-Block erzeugt, und die beim Verlassen der Prozedur/Funktion dann automatisch freigegeben werden.

Willst du das nicht, dann solltest du TInterfacedPersistent als Basisklasse nehmen. Hier muss das Objekt manuell wieder freigegeben werden. Dies ist für Klassen gedacht, die nicht ausschließlich der Implementierung eines Interfaces dienen sondern ein Interface ggf. einfach nur "zusätzlich" implementieren möchten.

Außerdem werfe ich nochmal die beiden Klassen TAggregatedObject und TContainedObject ins Rennen, die man als Basisklasse für Objekte mit Interfaces nehmen kann, die zu einem anderen Objekt mit Interface gehören (z.B. Elemente einer Aufzählung) und ihre Referenzzählung an das "besitzende" Objekte delegieren.
Volker
Besucht meine Garage
Aktuell: RtfLabel 1.3d, PrintToFile 1.4
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#6

Re: Destroy wird ohne Aufruf ausgeführt - total strange...

  Alt 14. Aug 2008, 11:15
Ich bin nun einfach mal so dreist und nutze deinen Quellcode, da der als Beispiel sehr gute passt
Delphi-Quellcode:
type
  ISomeInterface = interface
    procedure registerObject(aObject: TObject);
  end;

  TSomeInterface = class(TInterfacedObject, ISomeInterface)
  public
    FVar : TObject;
    procedure registerObject(aObject: TObject);
  end;


procedure TSomeInterface.registerObject(aObject: TObject);
begin
  FVar := aObject;
end,

// ...

procedure blaaa(aObject: TObject);
var
  tmp : TSomeInterface;
begin
  tmp := TSomeInterface.Create();
  tmp.registerObject(blub);

  // hier kommt nun die tolle Stelle
  FreeAndNil(tmp);
end;
So hab ich das in meinem Quellcode gemacht. Ich weiß nicht, was daran falsch sein soll bzw. es ist ja in so fern falsch, dass ab nach dem FreeAndNil(tmp) dann das Objekt blub ebenfalls zerstört wird. Auf das Objekt blub, welches irgendwo anders erzeugt worden ist, zeigt aber definitiv noch eine Referenz, da es in einer Liste (TList) eingetragen wurde. Ich weiß nun nicht, was genau das Interface mit meinem Objekten anstellt. Es kann ja nicht sein, dass auf alle Referenzen innerhalb es tmp-Objekts ein Free() oder FreeAndNil() automatisch angewendet wird?!

PS: Kennst du ein gutes Tutorial oder dergleichen, wo man das nachlesen kann?! Habe bisher eben noch kein gutes gefunden, wo drin stehst was wann und warum passiert!?

mit freundlichen Grüßen
Armin
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Benutzerbild von Flocke
Flocke

Registriert seit: 9. Jun 2005
Ort: Unna
1.172 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#7

Re: Destroy wird ohne Aufruf ausgeführt - total strange...

  Alt 14. Aug 2008, 12:25
Zitat von s.h.a.r.k:
Ich bin nun einfach mal so dreist und nutze deinen Quellcode, da der als Beispiel sehr gute passt
...ich schreibe dann mal weiter...

Wie ich oben schon schrieb: wenn das Objekt nur das Interface implementieren soll, dann benutze auch nur das Interface und nicht die Referenz auf das Objekt (s.u.). Solche zählenden Interfaces werden automatisch freigegeben, sobald sie nicht mehr benötigt werden.

Variante 1 wäre also einfach, ISomeInterface an Stelle von TSomeInterface zu benutzen:
Delphi-Quellcode:
procedure blaaa(aObject: TObject);
var
  tmp : ISomeInterface; // <-!
begin
  tmp := TSomeInterface.Create();
  tmp.registerObject(blub);

  // hier kommt nun die tolle Stelle
//FreeAndNil(tmp); // <-!
end;
Soll dein Objekt die Schnittstelle nur "nebenbei" mit implementieren, also nicht hauptsächlich oder ausschließlich dem Interface dienen, dann solltest du ganz einfach von TInterfacedPersistent (oder TComponent) ableiten:
Delphi-Quellcode:
  TSomeInterface = class(TInterfacedPersistent, ISomeInterface) // <-!
  public
    FVar : TObject;
    procedure registerObject(aObject: TObject);
  end;
Es hängt also davon ab, welchen Zweck dein Objekt bzw. dein Interface erfüllen soll.

Von TInterfacedObject abgeleitete Klasse sind -wie oben schon geschrieben- eigentlich für die ausschließliche Verwendung als Interfaces gedacht. Das Problem ist die Referenzzählung, die das Objekt automatisch freigibt, sobald der Zähler auf 0 abfällt (nachdem er mindestens ein Mal auf 1 hochging):
Delphi-Quellcode:
var
  T: TSomeInterface;
  I: ISomeInterface;
begin
  T := TSomeInterface.Create; // Zähler: 0
  I := T as ISomeInterface; // Zähler: 1
  I := nil; // Zähler: 0 --> Objekt wird freigegeben
  // ab hier ist T nicht mehr gültig
end;
Merkregel: Nachdem du ein von TInterfacedObject abgeleitetes Objekt einmal als Interface benutzt hast, solltest du es nicht mehr über die Objektreferenz ansprechen.

Zitat von s.h.a.r.k:
PS: Kennst du ein gutes Tutorial oder dergleichen, wo man das nachlesen kann?! Habe bisher eben noch kein gutes gefunden, wo drin stehst was wann und warum passiert!?
Tut mir leid, ein gutes Tutorial dazu habe ich auch noch nicht gefunden.
Volker
Besucht meine Garage
Aktuell: RtfLabel 1.3d, PrintToFile 1.4
  Mit Zitat antworten Zitat
xaromz

Registriert seit: 18. Mär 2005
1.682 Beiträge
 
Delphi 2006 Enterprise
 
#8

Re: Destroy wird ohne Aufruf ausgeführt - total strange...

  Alt 14. Aug 2008, 18:25
Hallo,

Tutorial Interfaces.

Gruß
xaromz
I am a leaf on the wind - watch how I soar
  Mit Zitat antworten Zitat
Antwort Antwort


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 05:22 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