![]() |
Kreuzreferenzen - selbsthaltende Interfaces
Einige kennen doch bestimmt das Problem, daß wenn sich Interfaces gegenseitig referenzieren,
daß diese, selbst bei Freigabe aller externen Referenzen, sich dennoch nicht freigeben, da sie sich ja gegenseitig halten.
Delphi-Quellcode:
Nja, da ich hiermit immer mal wieder Probleme hatte und deswegen oftmals sogar auf Interfaces verzichtete,
type
TObjektMaster = Class(InterfacedObject); FSlave: IInterface; End; TObjektSlave = Class(InterfacedObject); FMaster: IInterface; End; wollte ich endlich mal dafür eine befriedigende Lösung finden. Erstmal 2 "einfache" Varianten, bei welchen man Referenzen registrieren kann, welche praktisch nicht gezählt werden sollen.
Delphi-Quellcode:
type
IXRefInterface = Interface // register after set to the reference variable // unregister before free the reference variable Procedure RegisterXRef; Function UnregisterXRef: Boolean; // FALSE if the object was destroyed End; TXRefInterfacedObject = Class(TObject, IInterface, IXRefInterface) Protected {IInterface} Function QueryInterface(Const IID: TGUID; Out Obj): HResult; StdCall; Function _AddRef: Integer; StdCall; Function _Release: Integer; StdCall; Protected {IXRefInterface} FRefCount, FXRefs: Integer; Procedure RegisterXRef; Function UnregisterXRef: Boolean; // FALSE if the object was destroyed Procedure DoFreeXRefs; Virtual; Public Procedure AfterConstruction; Override; Procedure BeforeDestruction; Override; Class Function NewInstance: TObject; Override; Property RefCount: Integer Read FRefCount; End; Function TXRefInterfacedObject.QueryInterface(Const IID: TGUID; Out Obj): HResult; Begin If GetInterface(IID, Obj) Then Result := S_OK Else Result := E_NOINTERFACE; End; Function TXRefInterfacedObject._AddRef: Integer; Begin Result := InterlockedIncrement(FRefCount); End; Function TXRefInterfacedObject._Release: Integer; Begin Result := InterlockedDecrement(FRefCount); If Result = FXRefs Then Destroy; End; Procedure TXRefInterfacedObject.RegisterXRef; Begin InterlockedIncrement(FXRefs); End; Function TXRefInterfacedObject.UnregisterXRef: Boolean; Begin InterlockedDecrement(FXRefs); Result := FRefCount <> FXRefs; If not Result Then Destroy; End; Procedure TXRefInterfacedObject.DoFreeXRefs; Begin // do nothing End; Procedure TXRefInterfacedObject.AfterConstruction; Begin // release the constructor's implicit refcount InterlockedDecrement(FRefCount); End; Procedure TXRefInterfacedObject.BeforeDestruction; Begin If FRefCount <> FXRefs Then Error(reInvalidPtr); DoFreeXRefs; If FRefCount <> 0 Then Error(reInvalidPtr); End; Class Function TXRefInterfacedObject.NewInstance: TObject; Begin Result := Inherited NewInstance; TInterfacedObject(Result).FRefCount := 1; End;
Delphi-Quellcode:
type
IXRefInterface = Interface // release before free the reference variable Function GetNonCounteredReference: IInterface; Procedure ReleaseNonCounteredReference; End; TXRefInterfacedObject = Class(TObject, IInterface, IXRefInterface) Protected {IInterface} Function QueryInterface(Const IID: TGUID; Out Obj): HResult; StdCall; Function _AddRef: Integer; StdCall; Function _Release: Integer; StdCall; Protected {IXRefInterface} FRefCount, FXRefs: Integer; Function GetNonCounteredReference: IInterface; Procedure ReleaseNonCounteredReference; Procedure DoFreeXRefs; Virtual; Public Procedure AfterConstruction; Override; Procedure BeforeDestruction; Override; Class Function NewInstance: TObject; Override; Property RefCount: Integer Read FRefCount; End; Function TXRefInterfacedObject.QueryInterface(Const IID: TGUID; Out Obj): HResult; Begin If GetInterface(IID, Obj) Then Result := S_OK Else Result := E_NOINTERFACE; End; Function TXRefInterfacedObject._AddRef: Integer; Begin Result := InterlockedIncrement(FRefCount); End; Function TXRefInterfacedObject._Release: Integer; Begin Result := InterlockedDecrement(FRefCount); If Result = FXRefs Then Destroy; End; Function GetNonCounteredReference: IInterface; Begin InterlockedIncrement(FXRefs); Result := Self; End; Procedure ReleaseNonCounteredReference; Begin InterlockedDecrement(FXRefs); //If FRefCount = FXRefs Then Destroy; End; Procedure TXRefInterfacedObject.DoFreeXRefs; Begin // do nothing End; Procedure TXRefInterfacedObject.AfterConstruction; Begin // release the constructor's implicit refcount InterlockedDecrement(FRefCount); End; Procedure TXRefInterfacedObject.BeforeDestruction; Begin If FRefCount <> FXRefs Then Error(reInvalidPtr); DoFreeXRefs; If FRefCount <> 0 Then Error(reInvalidPtr); End; Class Function TXRefInterfacedObject.NewInstance: TObject; Begin Result := Inherited NewInstance; TInterfacedObject(Result).FRefCount := 1; End; Und dann noch eine Variante, bei welcher jeweils erneut durchgezählt wird, was wirklich frei ist.
Delphi-Quellcode:
type
TXRefInterfacedObject = Class(TObject, IInterface) Protected {IInterface} Function QueryInterface(Const IID: TGUID; Out Obj): HResult; StdCall; Function _AddRef: Integer; StdCall; Function _Release: Integer; StdCall; Protected FRefCount: Integer; Procedure DoCountingXRefs(Var Count: Integer); Virtual; Procedure DoFreeXRefs; Virtual; Public Procedure AfterConstruction; Override; Procedure BeforeDestruction; Override; Class Function NewInstance: TObject; Override; Property RefCount: Integer Read FRefCount; End; Function TXRefInterfacedObject.QueryInterface(Const IID: TGUID; Out Obj): HResult; Begin If GetInterface(IID, Obj) Then Result := S_OK Else Result := E_NOINTERFACE; End; Function TXRefInterfacedObject._AddRef: Integer; Begin Result := InterlockedIncrement(FRefCount); End; Function TXRefInterfacedObject._Release: Integer; Var XRefs: Integer; Begin XRefs := 0; DoCountingXRefs(XRefs); Result := InterlockedDecrement(FRefCount); If Result = XRefs Then Destroy; End; Procedure TXRefInterfacedObject.DoCountingXRefs(Var Count: Integer); Begin // do nothing End; Procedure TXRefInterfacedObject.DoFreeXRefs; Begin // do nothing End; Procedure TXRefInterfacedObject.AfterConstruction; Begin // release the constructor's implicit refcount InterlockedDecrement(FRefCount); End; Procedure TXRefInterfacedObject.BeforeDestruction; Var XRefs: Integer; Begin XRefs := 0; DoCountingXRefs(XRefs); If FRefCount <> XRefs Then Error(reInvalidPtr); DoFreeXRefs; If FRefCount <> 0 Then Error(reInvalidPtr); End; Class Function TXRefInterfacedObject.NewInstance: TObject; Begin Result := Inherited NewInstance; TInterfacedObject(Result).FRefCount := 1; End;
So, nun seid ihr gefragt. Wie würdet oder wie habt ihr solche Probleme gelöst, bzw. welche Variante (kann auch eine ganz Andere sein) würdet ihr bevorzugen und wo würdet ihr euer Pro und Contra setzen? |
Re: Kreuzreferenzen - selbsthaltende Interfaces
Man kann das "Sklavenobjekt" auch von TContainedObject anstatt TInterfacedObject ableiten.
Objekte dieser Klasse haben keinen eigenen Referenzzähler, sondern geben die Referenzen an ihren Master weiter. Als Konsequenz davon muss der Master alle von TContainedObject abgeleiteten Objekte manuell mit Free freigeben wenn er selbst zerstört wird. Das Masterobjekt und alle ContainedObjekte haben nach Aussen zwar mehrere Interfacezeiger verhalten sich aber wie ein Objekt bezügl. der Referenzzählung. Am Besten versteht man's wenn man den Sourcecode anschaut. |
Re: Kreuzreferenzen - selbsthaltende Interfaces
Hey, das klingt auch nicht so schlecht. :thumb:
Nur hätte ich da ein kleines "Problem", denn bei mir kann es vorkommen, daß ein Objekt als TContainedObject oder als TInterfacedObject behandelt werden mütße, jenachdem ob es einen "Master"/Parent gibt oder nicht. Aber ich denke das läßt sich leicht lösen, indem ich einfach diese beiden Objekte kombiniere. [edit] Das Kombinieren der Interfaces und eine Fallunterscheidung im Create ist kein Problem, aber wenn ich jetzt den Status wärend der Lebenszeit des Objektes ändern will/mußt, dann wird es schon schwerer. *grübel* [/edit] Die Variante über RegisterCallbacks scheint aber auch machbar zu sein. Mal sehn, vermutlich erstelle ich mir erstmal diese TInterfacedObject-TContainedObject-Kombination und falls es nötig ist, integriere ich mir noch diese Callbacks. :-D (hab ja noch etwas Zeit ... hatte mir diese Frage schon frühzeitig gestellt, bevor ich wieder mit diesen Interfaces anfange) |
Re: Kreuzreferenzen - selbsthaltende Interfaces
Zitat:
![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:42 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