将 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("|");
    }
}