我在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更好,也更容易,因为它清除整个结构(如果你有更多的字符串)。
答案 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。