为什么不收集TInterfacedObject垃圾的后代?

时间:2009-01-27 19:49:38

标签: delphi reference-counting tinterfacedobject

我有一个基于TInterfacedObject的类。我将它添加到TTreeNode的数据属性。

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

我创建了这个对象的许多实例&我认为因为他们的参考计数,我不应该释放他们。这很方便。

然而,在检查时,我打开了ReportMemoryLeaksOnShutdown,发现它们毕竟没有被释放。

这些对象是在放置在主窗体上的框架中创建的。在主窗体的FormClose中,我清除树节点,以便释放每个对象。

发生了什么事?

谢谢你的帮助!

3 个答案:

答案 0 :(得分: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属性访问对象,就会遇到访问冲突。

所以,在这种情况下不要打扰接口,你可以让它工作,但它会比它的价值更多的努力。

答案 1 :(得分: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;

要访问您的字段,您应该使用Getters和Setters在IFacilityTreeItem接口中声明属性。

答案 2 :(得分:2)

作为dummzeuch said,您可以使用它来使用接口,但由于TTreeNode的Data属性是指针,因此需要更多代码。对于想知道如何做到这一点的人来说,this link有一个如何为TListItem做这个的例子(对TTreeNode来说几乎是一样的)。您可能还会发现阅读有关interfaces的部分以及该页面上有关引用计数的后续部分非常有用。