将 CString 用于树节点时发生内存泄漏
Memory leak when using CString for tree node
我想在对话框中保存(序列化)一个 MFC 树控件,并在对话框初始化时调用它来填充树。我认为完成该任务的方法是首先编写一个程序来创建(最好)树的矢量表示,将其存储在文本文件中,然后通过从保存的文件反序列化来重新创建树表示。我也更愿意将节点保存为 CString,因为这是我用来保存和读取文件文本的方式。然而,我不仅不能靠这个上一垒,连球棒都拿不起来。以下使用 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;
}
…程序退出时报告内存泄漏。谁能解释一下原因,如果我能做些什么来纠正它呢?
您的原始迭代中似乎也存在内存泄漏(未使用 CString
)。您在堆上为 newNode(std::string)
中的 new Node
分配内存,但您永远不会在该指针上的任何地方调用 delete
。
只需在 main()
退出之前的某处 delete root;
来修复第一个内存泄漏。
接下来,您会发现一旦用指针填充了 vector<Node*> child
,这些指针也需要以某种方式删除。我建议向您的 struct Node
添加一个析构函数,它遍历 vector 并在其中的每个指针上显式调用 delete。
关于 CString
的注释
快速搜索 CString
的工作原理[1](因为我以前从未处理过它)表明当您复制 CString
(例如通过使用复制赋值运算符),不会创建新对象,但会在原始 CString
对象中增加引用计数器。只有当引用计数器达到零时,该对象才会被销毁。
因为你从来没有在你的 Node 指针上调用 delete
,所以 Node 对象中的 CString
对象永远不会被删除,这个引用号也永远不会减少。调用 delete 应该 解决问题,但请报告它是否解决了问题。
正如前面的回答和评论所指出的,必须有人释放所有分配的内存。
当您使用 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("|");
}
}
我想在对话框中保存(序列化)一个 MFC 树控件,并在对话框初始化时调用它来填充树。我认为完成该任务的方法是首先编写一个程序来创建(最好)树的矢量表示,将其存储在文本文件中,然后通过从保存的文件反序列化来重新创建树表示。我也更愿意将节点保存为 CString,因为这是我用来保存和读取文件文本的方式。然而,我不仅不能靠这个上一垒,连球棒都拿不起来。以下使用 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;
}
…程序退出时报告内存泄漏。谁能解释一下原因,如果我能做些什么来纠正它呢?
您的原始迭代中似乎也存在内存泄漏(未使用 CString
)。您在堆上为 newNode(std::string)
中的 new Node
分配内存,但您永远不会在该指针上的任何地方调用 delete
。
只需在 main()
退出之前的某处 delete root;
来修复第一个内存泄漏。
接下来,您会发现一旦用指针填充了 vector<Node*> child
,这些指针也需要以某种方式删除。我建议向您的 struct Node
添加一个析构函数,它遍历 vector 并在其中的每个指针上显式调用 delete。
关于 CString
的注释
快速搜索 CString
的工作原理[1](因为我以前从未处理过它)表明当您复制 CString
(例如通过使用复制赋值运算符),不会创建新对象,但会在原始 CString
对象中增加引用计数器。只有当引用计数器达到零时,该对象才会被销毁。
因为你从来没有在你的 Node 指针上调用 delete
,所以 Node 对象中的 CString
对象永远不会被删除,这个引用号也永远不会减少。调用 delete 应该 解决问题,但请报告它是否解决了问题。
正如前面的回答和评论所指出的,必须有人释放所有分配的内存。
当您使用 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("|");
}
}