![]() |
Delphi-Version: XE2
RefCount nach Erstellung von TInterfacedObject gleich 0
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen,
ich habe gerade ein irgendwie unschönes Problem mit Interfaces. Gehe um Moment immer mehr dazu über Interfaces zu verwenden, da es an einigen Stellen echt praktisch sein kann. Dann gibt es aber immer wieder merkwürdige Dinge, die ich (noch) nicht so recht verstehe... Und zwar geht um im Moment um den folgenden Code -- ja, der ist leicht anders als der auf dem Bild im Anhang!
Delphi-Quellcode:
Ich finde, dass da ja nichts besonderes dran ist. Mit der lokalen Variablen muss ich arbeiten, da die AddStartupCommands einen Parameter vom Typ TBaseStartupProcess erwartet -- das Interface kann ich hier nicht nutzen, da ich in der AddStartupCommands Dinge mit dem Objekt mache, die nicht vom Interface abgedeckt sind.
TBaseStartupProcess = class(TInterfacedObject, IStartupProcess, IStartupProcessCommandContainer)
end; class function TStartupManagerFactory.Create(): IStartupProcess; var StartupProcess : TBaseStartupProcess; begin StartupProcess := TBaseStartupProcess.Create(); AddStartupCommands(StartupProcess); Result := StartupProcess; end; Jedenfallst ist es so, dass wenn ich obigen Code verwende, direkt nach der AddStartupCommands-Methode, die Destroy-Methode von StartupProcess aufgerufen wird. Habe das dann weiter verfolgt und bin darauf gestoßen, dass direkt nach dem Erzeugen des Objekts RefCount gleich 0 ist. Hier die Frage: wie kann sowas sein? StartupProcess zeigt doch auf das neu erzeugte Objekt, ergo müsste doch RefCount gleich 1 sein -- im Screenshot könnt ihr das auch nochmals sehen. Wenn ich den Code umstelle, wie im Screenshot gezeigt, so ist alles in Butter und die Destroy-Methode wird nach dem Aufruf von AddStartupCommands nicht aufgerufen, da RefCount nach der Zuweisung
Delphi-Quellcode:
1 ist, und nicht 0.
Result := StartupProcess;
Ich hoffe, dass hier jemand Licht ins Dunkel bringen kann! |
AW: RefCount nach Erstellung von TInterfacedObject gleich 0
Die Referenzzählung erfolgt IMHO erst dann, wenn die Instanz zu einer Interface-Variablen zugeordnet wird.
Probier es mal so
Delphi-Quellcode:
class function TStartupManagerFactory.Create(): IStartupProcess;
var StartupProcess : TBaseStartupProcess; begin StartupProcess := TBaseStartupProcess.Create(); Result := StartupProcess; AddStartupCommands(StartupProcess); // Hier mal den Haltepunkt setzen und prüfen end; |
AW: RefCount nach Erstellung von TInterfacedObject gleich 0
Zitat:
Möglicherweise hiermit: Die Erklärung dazu könnte durch ein Problem verursacht sein, das detailliert hier beschrieben worden ist: Kosch, Andreas: "COM/DCOM/COM+ mit Delphi" (ISBN 3-935042-01-9), p.92-94. Kurz zusammengefasst: Es liegt womöglich an der Verwendung der "normalen" Delphi-Variablen StartupProcess: TBaseStartupProcess für den Zugriff auf das interfaced Objekt innerhalb der function TStartupManagerFactory.Create() anstatt, wie es richtiger wäre, der Verwendung unmittelbar einer echten Interface-Variablen (StartupProcess : IDingsbums) für das COM-Objekt. Details siehe genannte Referenz. Von Kosch vorgeschlagener Workaround: den Verwendungszähler des COM-Objekts manuell durch Aufruf von _Addref um 1 hochzählen. |
AW: RefCount nach Erstellung von TInterfacedObject gleich 0
RefCount sagt nicht aus wie oft das Objekt verwendet wird, sondern wie viele Interface-Variablen existieren, die auf dieses Objekt verweisen. Deshalb ist RefCount nach dem Erzeugen erst einmal 0. Das Objekt wird nur automatisch freigegeben, wenn RefCount von 1 auf 0 fällt.
Arbeitet AddStartupCommands() durchgehend nur mit dem Objekt, so ist alles in Ordnung. Aber vermutlich wird das Objekt dort auch einer Interfacevariable zugewiesen, die nur temporär existiert. Dadurch steigt RefCount und fällt wieder auf 0, mit dem bekannten Ergebnis. Zitat:
Die Variante von Sir Rufo funktioniert auch. Allerdings sollte man solche Kniffe ausführlich kommentieren. Sonst wundert man sich, wenn man an dieser Stelle z.B. in zwei Jahren nur eine Kleinigkeit ändert, warum nichts mehr geht... |
AW: RefCount nach Erstellung von TInterfacedObject gleich 0
Wenn mit Interfaces gearbeitet wird, dann sollte dieses durchgängig gemacht werden.
Delphi-Quellcode:
Standardmäßig ist eine Mischbehandlung nicht sicher, da die Referenzzählung keine Ahnung davon hat, ob irgendwo Variablen Referenzen auf das Objekt besitzen, da nur Referenzen auf das Interface gezählt werden.
class function TStartupManagerFactory.Create(): IStartupProcess;
begin Result := TBaseStartupProcess.Create(); Result := StartupProcess; AddStartupCommands(Result); end; Wie ist denn AddStartupCommands deklariert? (der Parameter als Interface oder als Objekt) |
AW: RefCount nach Erstellung von TInterfacedObject gleich 0
Zitat:
Wo kann etwas schiefgehen, wenn man wie im Beispiel der Factoryklasse, die erzeugte Instanz temporär in einer lokalen Variable speichert? |
AW: RefCount nach Erstellung von TInterfacedObject gleich 0
Wenn du dir mal die Implementation von TInterfacedObject ansiehst, kannst du sehen, wie in NewInstance der RefCount auf 1 gesetzt wird und in AfterConstruction wieder um 1 verringert wird. Wenn also nicht innerhalb des Create ein implizites _AddRef erfolgt, ist der RefCount nach dem Create wieder 0. Das muss auch so sein, da er sonst ja nie mehr auf 0 kommen könnte und die Instanz nicht mehr freigegeben würde. Die Zuweisung der Instanz auf eine simple Variable dieser Klasse oder einer Oberklasse löst übrigens keine implizite Referenzzählung aus (wie Sir Rufo richtig bemerkt hat), dies geht nur bei Interface-Variablen und -Parametern.
Das erste was also passieren muss, ist die Instanz einer Interface-Variablen (z.B. dem result) zuzuweisen, damit der RefCount erhöht wird. Vorher kannst du mit der Instanz eigentlich nur sehr wenig anfangen. Auf gar keinen Fall darf dabei ein _AddRef/_Release aufgerufen werden (was offenbar irgendwo innerhalb der Methode AddStartupCommands passiert), da sonst die Instanz sofort freigegeben wird. Deine lokale Instanzvariable zeigt dann eben ins Nirwana. Diese Krücke mit dem künstliche hochzählen während des Create macht man übrigens eben deshalb, damit solche impliziten Interface-Zuweisungen innerhalb der Create-Sequenz nicht gleich zur Zerstörung der Instanz führen. Inkonsequenterweise hat man dies für die Destroy-Sequenz wohl vergessen. |
AW: RefCount nach Erstellung von TInterfacedObject gleich 0
So solte das doch eigentlich funktionieren
Delphi-Quellcode:
class function TStartupManagerFactory.Create(): IStartupProcess;
begin Result := TBaseStartupProcess.Create(); AddStartupCommands( TBaseStartupProcess( Result ) ); end; |
AW: RefCount nach Erstellung von TInterfacedObject gleich 0
Zitat:
Ein Interface-Zeiger ist kein Objekt-Zeiger, also kann man das nicht einfach so billig umcasten. Zitat:
Sobald man auch nur eine Interfacevariable erstellt ht, ist die Zuferlässigkeit von Objektzeigern nicht mehr gegeben, da das Objekt vorzeitig/ungewollt über die Interface-Referenzzählung freigegeben werden könnte. Aus diesem Grund hatte ich vor eine Weile angefangen eine Hybride zu erstellen, welche die Interfacereferenzen und Objektreferenzen gleichermaßen beachtet. Leider ist das in Delphi (speziell die Erstellung des Objektes) nicht komplett und sicher umsetzbar, da man nicht automatisch erkennen kann, ob das erstellte Objekt, bei
Delphi-Quellcode:
direkt in eine Interfacevariable geht oder ob das eine Objektvariable ist. (also um was es sich beim X handelt)
x := TIrgendwas.Create;
|
AW: RefCount nach Erstellung von TInterfacedObject gleich 0
Zitat:
Aus diesem Grunde mache ich das so ... und es funktioniert :mrgreen: Also, das sollte nicht nur, sondern das Casten funktioniert genau so. Eine Hummel kann eigentlich gar nicht fliegen, da die Flügel viel zu klein für ihr Gewicht sind. Da die Hummel das nicht weißt, fliegt sie einfach. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:22 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