2008-10-05 83 views
4

我有一個接口的小問題。這裏是僞代碼:接口「遞歸」和引用計數

type 
    Interface1 = interface 
    end; 

    Interface2 = interface 
    end; 

    TParentClass = class(TInterfacedObject, Interface1) 
    private 
    fChild : Interface2; 
    public 
    procedure AddChild(aChild : Interface2); 
    end; 

    TChildClass = class(TInterfacedObject, Interface2) 
    private 
    fParent : Interface2; 
    public 
    constructor Create(aPArent : Interface1); 
    end; 

任何人都可以看到缺陷嗎?我需要孩子參考其父母,但引用計數在這種情況下不起作用。如果我創建一個ParentClass實例並添加一個子項,那麼父類永遠不會被釋放。我明白爲什麼。我如何繞過它?

+0

請參閱http://stackoverflow.com/questions/487311/how-to-implement-reference-counted-objects-in-delphi#487387,以獲得有關使用Delphi界面的循環引用問題的完整答案。 – 2012-02-01 17:28:15

+0

使用真正的GC代替引用計數。 – 2008-11-24 18:40:25

回答

10

引用計數引用有兩個語義:它充當所有權的份額以及導航對象圖的方式。

通常,您不需要這兩種語義的在引用圖的一個循環中的所有鏈接上。也許只有父母擁有孩子,而不是相反?如果是這樣的話,就可以讓孩子引用到父薄弱環節,通過將它們存儲爲指針,就像這樣:

TChildClass = class(TInterfacedObject, Interface2) 
private 
    fParent : Pointer; 
    function GetParent: Interface1; 
public 
    constructor Create(aPArent : Interface1); 
    property Parent: Interface1 read GetParent; 
end; 

function TChildClass.GetParent: Interface1; 
begin 
    Result := Interface1(fParent); 
end; 

constructor TChildClass.Create(AParent: Interface1); 
begin 
    fParent := Pointer(AParent); 
end; 

這是安全的,如果實例的樹的根是保證在某個地方保持活力,也就是說,你並不僅僅依靠保持對樹的一個分支的引用,而仍然能夠瀏覽整個樹的分支。

1

您必須制定明確取消鏈接正確引用的方法。在這種情況下無法正確使用自動引用計數。

+0

明確的方法是不必要的;它取決於所需的參考語義。 – 2008-10-05 10:23:40

3

那麼,參考計數當然是確實在這種情況下工作 - 它只是沒有解決問題。

這是引用計數的最大問題 - 當你有一個循環引用時,你必須明確地'打破'它(例如,設置一個接口引用爲'nil')。這也是爲什麼引用計數不是真正取代垃圾收集的原因 - 垃圾收集器意識到循環可能存在,並且可以在未從「外部」引用時釋放這樣的循環結構。

0

通過在第一個例子中使用函數指針,那麼循環引用問題就不存在了。 .NET使用委託,VB6使用事件。所有這些都有利於不增加被指向的對象的引用計數。