对树节点使用 CString 时出现内存泄漏

Memory leak when using CString for tree node

本文关键字:内存 泄漏 CString 树节点      更新时间:2023-10-16

我想在对话框中保存(序列化(MFC树控件,并在初始化对话框时调用它以填充树。 我认为处理该任务的方法是首先编写一个程序,该程序创建树的(最好(矢量表示,将其存储在文本文件中,然后通过从保存的文件反序列化来重新创建树表示。 我也更愿意将节点保存为 CStrings,因为这是我习惯于保存和读取文件中文本的方式。 然而,我不仅不能在这个基础上到达一垒,我甚至不能拿起球棒。 以下使用 std::string 创建单个节点的最小代码运行正常。

#include <string>
#include <vector>
// A node of N-ary tree 
struct Node {
std::string key;
std::vector<Node*> child;  // An array of pointers for children 
};
// A utility function to create a new N-ary tree node 
Node* newNode(std::string key)
{
Node* temp = new Node;
temp->key = key;
return temp;
}
// A utility function to create a tree
Node* createTree()
{
Node* root = newNode( "Root" );
return root;
}
int main()
{
Node* root = createTree();
return 0;    
}

但是如果我将其更改为使用 CString,

#include <afx.h>
#include <tchar.h>
#include <vector>
struct Node {
CString key;
std::vector<Node*> child;  // An array of pointers for children 
};
Node* newNode(CString key)
{
Node* temp = new Node;
temp->key = key;
return temp;
}
Node* createTree()
{
Node* root = newNode( _T("Root") );
return root;
}

。当程序退出时,它会报告内存泄漏。有人可以解释一下为什么,如果我能做些什么来纠正它?

正如前面的答案和评论所指出的,有人必须释放所有分配的内存。

当您使用new时,责任在于您。

但是,C++提供了智能指针,可以为您管理内存分配和释放;请参阅 https://en.cppreference.com/w/cpp/memory/unique_ptr。

您的示例代码将如下所示:

#include <atlstr.h>
#include <tchar.h>
#include <vector>
#include <memory>
struct Node {
CString key;
std::vector<std::unique_ptr<Node>> child;  
};
std::unique_ptr<Node> newNode(CString key)
{
std::unique_ptr<Node> temp = std::make_unique<Node>();
temp->key = key;
return temp;
}
std::unique_ptr<Node> createTree()
{
std::unique_ptr<Node> root = newNode(_T("Root"));
root->child.push_back(newNode(_T("Child")));
return root;
}

在评论中附加每个问题:

CString encode(std::unique_ptr<Node>& root)
{
if (root == nullptr)
return _T("");
{
CString sRep = root->key;
for (auto& temp : root->child)
sRep += encode(temp);
return sRep += _T("|");
}
}

您的原始迭代中似乎也有内存泄漏(不使用CString(。你在堆上为newNode(std::string)中的new Node分配内存,但你从不调用delete

只需在退出之前delete root;某个地方main()即可修复第一个内存泄漏。

接下来,您会发现一旦使用指针填充vector<Node*> child,也需要以某种方式删除这些指针。我建议在你的struct Node中添加一个析构函数,它遍历向量并显式调用 delete。

关于CString的说明

快速搜索CString的工作原理[1](因为我以前从未处理过它(表明,当您创建CString的副本(例如使用复制赋值运算符(时,不会创建新对象,但在原始CString对象中会递增引用计数器。仅当引用计数器达到零时,才会销毁该对象。

由于您永远不会在 Node 指针上调用delete,因此永远不会删除 Node 对象中的CString对象,并且永远不会减少此引用编号。调用删除应该可以解决问题,但请报告是否可以解决问题。