VirtualTreeView在C ++ Builder中为UnicodeString完成

时间:2012-04-16 23:55:29

标签: c++ delphi memory-leaks c++builder virtualtreeview

我在C ++ Builder中使用VirtualTreeView并使用结构如下:

struct TVTNodeData
   {
   int Index;
   UnicodeString Caption;
   }

我使用具有以下内容的循环预填充树的节点:

TVirtualNode *Node = VTree->AddChild(NULL);
pNode = (TVTNodeData *)VTree->GetNodeData(Node);
pNode->Index = 1;
pNode->Caption = "Whatever";

我注意到应用程序的内存不断增加(内存泄漏),即使我清除树并重新加载它。此页面 - http://www.remkoweijnen.nl/blog/2010/06/09/memory-leaks-when-using-virtual-treeview-component/建议在OnFreeNode事件中执行Finalize()。好到目前为止。

但是C ++中没有Finalize()。我在pNode->Caption=""事件中尝试了OnFreeNode,并且不再大量分配内存,但它仍然有点。我认为即使它被清空也可能会引用UnicodeString(引用计数> 0)。

如何在C ++中为UnicodeString释放OnFreeNode事件中的节点数据?我知道UnicodeString是在所有引用计数为零之前分配的 - 那么如何强制引用计数变为零?

此外,如果在OnNodeInit中分配了节点,那么OnFreeNode事件是否同样适用?

如果TVTNodeData结构纯粹是虚拟的 - 那么节点永远不可见也不会使用AddChild和OnNodeInit进行初始化,然后需要Finalize,结构是否存在于内存中呢?

更新:我后来发现我正在测量内存使用情况不正确,而字符串将它们设置为空字符串就足以清除内存数据了。但是 - 正如Rob Kennedy在下面的回答中所建议的那样,调用struct~destructor比使用Finalize更好,也更容易,因为它清除整个结构(如果你有更多的字符串)。

2 个答案:

答案 0 :(得分:8)

Delphi的Finalize具有释放记录中任何编译器管理类型的效果。在C ++中,这通常是类型的析构函数的工作。在OnFreeNode事件处理程序中,直接调用数据类型的析构函数:

TVTNodeData* const pNode = static_cast<TVTNodeData*>(Sender->GetNodeData(Node));
pNode->~TVTNodeData();

这将调用UnicodeString对象的析构函数,它将释放相关的字符数据。当树控件为节点分配TVTNodeData时,它与TVirtualNode对象本身位于同一块内存中,因此您不能只调用delete

树控件使用all-bits-zero初始化数据。如果您的数据中有一个对象不是正确的初始化(哪个正式正确,包括所有非POD类型),那么您应该调用构造函数 OnInitNode事件中的数据。使用展示位置来执行此操作。例如:

TVTNodeData* const pNode = static_cast<TVTNodeData*>(Sender->GetNodeData(Node));
new (pNode) TVTNodeData();

这将调用TVTNodeData成员的构造函数,而不为其他TVTNodeData实例分配内存。

如果一个节点从未被初始化,那么它也不会被最终确定。 OnInitNode事件将永远不会运行,因此树将知道该节点尚未初始化。未初始化的节点无法完成,因此您无需担心。

答案 1 :(得分:2)

我认为并非所有节点都经过验证,可能是因为它们没有显示。尝试在AddChild之后调用ValidateNode。