2009-01-27 54 views
4

我有一個基於TInterfacedObject的類。我將它添加到TTreeNode的Data屬性中。爲什麼不收集TInterfacedObject垃圾的後代?

TFacilityTreeItem=class(TInterfacedObject) 
private 
    m_guidItem:TGUID; 
    m_SomeOtherNode:TTreeNode; 
public 
end; 

我創建這個對象&的許多情況下,曾以爲,因爲他們是引用計數的,我不應該需要釋放他們。那會很方便。然而,當檢查這個時,我打開了ReportMemoryLeaksOnShutdown,發現它們並沒有被釋放。

這些對象是在放置在主窗體上的框架中創建的。在主窗體的FormClose中,我清除樹節點,以便每個對象都應該被釋放。

發生了什麼事?

謝謝你的幫助!

回答

16

TInterfacedObject本身沒有引用計數,只有接口是。您可以使用TInterfacedObject實現接口,這基本上可以節省您自己實現引用計數方法的工作量。不幸的是,它仍然不能用於你的情況:編譯器不知道你將接口分配給TTreeNode.Data屬性,因爲它沒有被聲明爲接口,而是作爲指針。所以各種奇怪的事情將發生:

MyInt := TFacilityTreeItem.Create; // ref count = 1 
// Node.Data := MyInt; // won't compile 
Node.Data := pointer(MyInt); // no interface assignment, ref count stays 1 
... 
end; // ref count reaches 0, your object gets freed 

只要您嘗試通過.Data屬性訪問您的對象,您將得到一個訪問衝突。

所以,在這種情況下,不要打擾接口,你可以讓它工作,但它會比它的價值更多的努力。

+0

謝謝你的回答;我將使用TObject代替。學到了新東西! – 2009-01-27 22:13:19

3

你應該聲明字段/變量作爲接口

IFacilityTreeItem = IInterface 
end; 

TFacilityTreeItem=class(TInterfacedObject, IFacilityTreeItem) 
private 
    m_guidItem:TGUID; 
    m_SomeOtherNode:TTreeNode; 
end; 

var 
    Item: IFacilityTreeItem; // Variable as Interface 
begin 
    Item:= TFacilityTreeItem.Create; 
... 
end; 

要訪問你的領域,你應該在IFacilityTreeItem接口聲明屬性,與getter和setter。

+0

謝謝你的回答。我不喜歡讓getters/setter,所以我想我會讓它從TObject下降。 – 2009-01-27 22:10:59

+0

@Cesar Romero:請編輯你的代碼,它永遠不會編譯(接口不能有數據成員,也不會有任何私有的)。 – mghie 2009-01-27 22:48:22

2

由於dummzeuch said,你可以得到這個接口的工作,但它需要更多的代碼,因爲TTreeNode的Data屬性是一個指針。對於任何人想知道如何做到這一點,this link有一個如何做TListItem的例子(它與TTreeNode幾乎相同)。您也可能會發現閱讀關於interfaces的部分以及關於該頁面上引用計數的後續部分很有用。