4

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

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

我创建了这个对象的许多实例并假设因为它们是引用计数的,所以我不需要释放它们。那会很方便。

但是,当检查这个时,我打开了 ReportMemoryLeaksOnShutdown 并发现它们毕竟没有被释放。

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

发生了什么?

感谢您的帮助!

4

3 回答 3

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 属性访问您的对象,您就会遇到访问冲突。

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

于 2009-01-27T20:15:33.163 回答
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;

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

于 2009-01-27T21:28:39.053 回答
2

正如dummzeuch 所说,你可以让它与接口一起工作,但它需要更多的代码,因为 TTreeNode 的 Data 属性是一个指针。对于任何想知道如何做到这一点的人,此链接有一个如何为 TListItem 做的示例(对于 TTreeNode 几乎相同)。您可能还会发现阅读该页面上有关接口的部分和后续有关引用计数的部分很有用。

于 2009-02-17T06:55:39.037 回答