简体   繁体   English

使用 CString 作为树节点时 Memory 泄漏

[英]Memory leak when using CString for tree node

I would like to save (serialize) an MFC tree control in a dialog and recall it to populate the tree when the dialog is initialized.我想在对话框中保存(序列化)一个 MFC 树控件,并在初始化对话框时调用它以填充树。 I thought the way to approach that task would be to first code a program that creates a (preferably) vector representation of the tree, stores it in a text file, and then recreates the tree representation by deserializing from the saved file.我认为完成该任务的方法是首先编写一个程序,该程序创建一个(最好是)树的向量表示,将其存储在一个文本文件中,然后通过从保存的文件中反序列化来重新创建树表示。 I would also prefer to save the nodes as CStrings because that's how I'm used to saving and reading text from files.我还希望将节点保存为 CStrings,因为这就是我习惯从文件中保存和读取文本的方式。 However, not only can I not get to first base on this, I can't even pick up the bat.然而,我不仅不能达到第一垒,我什至不能拿起球棒。 The following minimal code to create a single node using std::string runs ok.以下使用 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;    
}

But if I change it to use CString instead,但是,如果我将其更改为使用 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;
}

…when the program exits it reports a memory leak. …当程序退出时,它会报告 memory 泄漏。 Could someone please explain why, and what if anything I can do to correct it?有人可以解释为什么,如果我能做些什么来纠正它?

It appears you have a memory leak in your original iteration as well (without using CString ).看来您在原始迭代中也有 memory 泄漏(不使用CString )。 You allocate memory on the heap for a new Node in newNode(std::string) , but you never call delete on that pointer anywhere.您在堆上为newNode(std::string)中的new Node分配 memory ,但您永远不会在任何地方对该指针调用delete

Simply delete root;只需delete root; somewhere before main() exits to fix this first memory leak.main()退出以修复第一个 memory 泄漏之前的某个地方。

Next, you'll find that once you populate the vector<Node*> child with pointers, those will need to be deleted somehow as well.接下来,您会发现一旦使用指针填充vector<Node*> child ,这些指针也需要以某种方式删除。 I suggest adding a destructor to your struct Node that iterates through vector and explicitly calls delete on each pointer in there.我建议向您的struct Node添加一个析构函数,该析构函数遍历向量并在其中的每个指针上显式调用删除。

A note on CString关于CString的注释

A quick search about how CString works [1] (because I've never dealt with it before) indicates that when you make a copy of a CString (such as by using the copy assignment operator), a new object isn't created, but a reference counter is incremented in the original CString object.快速搜索一下CString的工作原理[1] (因为我以前从未处理过它)表明当您复制CString时(例如使用复制赋值运算符),不会创建新的 object,但在原始CString object 中增加了一个引用计数器。 The object is only destroyed once that reference counter reaches zero. object 只有在引用计数器达到零时才会被销毁。

Since you're never calling delete on your Node pointer, the CString object in the Node object is never deleted, and this reference number is never decreased.由于您从未在 Node 指针上调用delete ,因此 Node object 中的CString object 永远不会被删除,并且此参考编号永远不会减少。 Calling delete should fix the problem, but please report back whether or not it does.调用 delete应该可以解决问题,但请报告是否可以解决。

As the previous answer and comments noted, someone has to free all allocated memory.正如前面的回答和评论所指出的,有人必须释放所有分配的 memory。

When you use new , the responsibility is on you.当你使用new时,责任就在你身上。

However, C++ provides smart pointers that can manage memory allocation and freeing for you;但是,C++ 提供了智能指针,可以为您管理 memory 的分配和释放; please see https://en.cppreference.com/w/cpp/memory/unique_ptr .请参阅https://en.cppreference.com/w/cpp/memory/unique_ptr

Your sample code will look like this:您的示例代码将如下所示:

#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;
}

APPENDED per question in the comment:附加评论中的每个问题:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM