AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi RefCount nach Erstellung von TInterfacedObject gleich 0
Thema durchsuchen
Ansicht
Themen-Optionen

RefCount nach Erstellung von TInterfacedObject gleich 0

Ein Thema von s.h.a.r.k · begonnen am 13. Jan 2012 · letzter Beitrag vom 13. Jan 2012
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von s.h.a.r.k
s.h.a.r.k

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

RefCount nach Erstellung von TInterfacedObject gleich 0

  Alt 13. Jan 2012, 15:12
Delphi-Version: XE2
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:
TBaseStartupProcess = class(TInterfacedObject, IStartupProcess, IStartupProcessCommandContainer)
end;

class function TStartupManagerFactory.Create(): IStartupProcess;
var
  StartupProcess : TBaseStartupProcess;
begin
  StartupProcess := TBaseStartupProcess.Create();
  AddStartupCommands(StartupProcess);
  Result := StartupProcess;
end;
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.

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 Result := StartupProcess; 1 ist, und nicht 0.

Ich hoffe, dass hier jemand Licht ins Dunkel bringen kann!
Miniaturansicht angehängter Grafiken
interface-refcount.png  
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: RefCount nach Erstellung von TInterfacedObject gleich 0

  Alt 13. Jan 2012, 16:05
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;
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
ASM

Registriert seit: 16. Aug 2004
165 Beiträge
 
Delphi 7 Enterprise
 
#3

AW: RefCount nach Erstellung von TInterfacedObject gleich 0

  Alt 13. Jan 2012, 16:06
... 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...

Ich hoffe, dass hier jemand Licht ins Dunkel bringen kann!

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.
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.477 Beiträge
 
Delphi 12 Athens
 
#4

AW: RefCount nach Erstellung von TInterfacedObject gleich 0

  Alt 13. Jan 2012, 16:11
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:
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.
Gegen die lokale Variable ist im Prinzip nichts einzuwenden, wenn diese für die Initialisierung des Objektes notwendig ist. Sobald aber ein Interface erzeugt ist, sollte man nur noch damit arbeiten. Wenn AddStartupCommands Dinge von dem Objekt erwartet, die durch die vorhandenen Interfaces nicht abgedeckt werden, so könnte man einfach ein weiteres Interface hinzufügen.

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...
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#5

AW: RefCount nach Erstellung von TInterfacedObject gleich 0

  Alt 13. Jan 2012, 16:21
Wenn mit Interfaces gearbeitet wird, dann sollte dieses durchgängig gemacht werden.
Delphi-Quellcode:
class function TStartupManagerFactory.Create(): IStartupProcess;
begin
  Result := TBaseStartupProcess.Create();
  Result := StartupProcess;
  AddStartupCommands(Result);
end;
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.

Wie ist denn AddStartupCommands deklariert?
(der Parameter als Interface oder als Objekt)
$2B or not $2B
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.006 Beiträge
 
Delphi 2009 Professional
 
#6

AW: RefCount nach Erstellung von TInterfacedObject gleich 0

  Alt 13. Jan 2012, 16:37
Wenn mit Interfaces gearbeitet wird, dann sollte dieses durchgängig gemacht werden.
Natürlich, aber irgendwo muss halt doch eine implementierende Klasse instanziiert werden.
Wo kann etwas schiefgehen, wenn man wie im Beispiel der Factoryklasse, die erzeugte Instanz temporär in einer lokalen Variable speichert?
Michael Justin
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#7

AW: RefCount nach Erstellung von TInterfacedObject gleich 0

  Alt 13. Jan 2012, 17:00
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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#8

AW: RefCount nach Erstellung von TInterfacedObject gleich 0

  Alt 13. Jan 2012, 17:11
So solte das doch eigentlich funktionieren
Delphi-Quellcode:
class function TStartupManagerFactory.Create(): IStartupProcess;
begin
  Result := TBaseStartupProcess.Create();
  AddStartupCommands( TBaseStartupProcess( Result ) );
end;
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#9

AW: RefCount nach Erstellung von TInterfacedObject gleich 0

  Alt 13. Jan 2012, 17:48
So solte das doch eigentlich funktionieren
Wenn hier nicht zufällig ein bissl Compilermagic mitspielt, dann definitiv NEIN.

Ein Interface-Zeiger ist kein Objekt-Zeiger, also kann man das nicht einfach so billig umcasten.

Zitat von mjustin:
Natürlich, aber irgendwo muss halt doch eine implementierende Klasse instanziiert werden.
Wo kann etwas schiefgehen, wenn man wie im Beispiel der Factoryklasse, die erzeugte Instanz temporär in einer lokalen Variable speichert?
Möglichst direkt in die Interfacevariable reinerstellen.

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 x := TIrgendwas.Create; direkt in eine Interfacevariable geht oder ob das eine Objektvariable ist. (also um was es sich beim X handelt)
$2B or not $2B

Geändert von himitsu (13. Jan 2012 um 17:55 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#10

AW: RefCount nach Erstellung von TInterfacedObject gleich 0

  Alt 13. Jan 2012, 17:59
So solte das doch eigentlich funktionieren
Wenn hier nicht zufällig ein bissl Compilermagic mitspielt, dann definitiv NEIN.

Ein Interface-Zeiger ist kein Objekt-Zeiger, also kann man das nicht einfach so billig umcasten.
Oh, dann habe ich wohl das Hummel-Syndrom ... denn das wusste ich nicht.
Aus diesem Grunde mache ich das so ... und es funktioniert

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.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 08:35 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