简体   繁体   English

在n元树中创建/访问节点时发生内存泄漏

[英]Memory leak when creating/accessing nodes in n-ary tree

I'm getting memory leaks from the following code: 我从以下代码获取内存泄漏:

struct Node {
    Node *children[20];
    int value;

    Node();
    ~Node();
};

Node::Node() {
    for(int i=0; i<20; i++) {
        children[i] = NULL;
    }
}

void Node::insert(int x) {
    Node *n = this;
    for(int i=0; i<20; i++) {
        if(n->children[i] == NULL) {
            n->children[i] = new Node();
            n->children[i]->value = x;
        }
        n = n->children[i];
    }
}  

Checking with Valgrind, apparently I'm getting a leak from this line: 检查Valgrind,显然我从这条线泄漏:

n->children[i] = new Node();

Is this a wrong way to use the constructor? 这是使用构造函数的错误方法吗?
Or is the Valgrind check misleading? 还是Valgrind支票有误导性?

Valgrind Error message: Valgrind错误消息:

505 (448 direct, 57 indirect) bytes in 2 blocks are definitely lost in loss record 2 of 3
  at 0x4C2B1C7: operator new(unsigned long)
  by 0x401A4F: Node::insert
  by 0x4015FA: main

LEAK SUMMARY:
  definitely lost: 448 bytes in 2 blocks
  indirectly lost: 57 bytes in 2 blocks
    possibly lost: 0 bytes in 0 blocks
  still reachable: 72,704 bytes in 1 blocks
       suppressed: 0 bytes in 0 blocks

ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)  

The Destructor I have: 我拥有的析构函数:

Node::~Node() {
    for(int i=0; i<20; i++) {
        delete children[i];
        children[i] = NULL;
    }
}

In main: 在主要方面:

int main() {
    Node *n = new Node();

    .
    .
    .

    delete n;
    n = NULL;

    return 0;
}

You are not deleting the children. 您没有删除孩子。 As answered by Axel, you should add a delete in your destructor. 正如Axel回答的那样,您应该在析构函数中添加一个删除。 Or better, use an array of unique_ptr, that will take care of destroying the nodes when they get out of scope. 或更妙的是,使用unique_ptr数组,该数组将在节点超出范围时销毁节点。

You never delete children pointers. 您永远不会删除子指针。

You should delete each allocated pointer of children array in the Node class destructor. 您应该删除Node类析构函数中子数组的每个分配指针。

Like that : 像那样 :

Node::~Node()
{
    for (int i = 0; i < 20; ++i)
    {
        delete children[i];
    }
}

Moreover, if there is any other method which replace pointers in children array, you have to delete the previous pointer before replacing it, like that: 此外,如果还有其他方法可以替换子数组中的指针,则必须先删除之前的指针,然后再执行以下操作:

...
delete n->children[i];
n->children[i] = new Node();
...

or 要么

...
delete n->children[i];
n->children[i] = p;  // where p is a pointer of Node
...

For information, you have to call delete to destroy and deallocate each object you construct on the heap (using new ). 有关信息,您必须调用delete来销毁和释放在堆上构造的每个对象(使用new )。

You could also use smartpointer to avoid to manage children members destruction. 您也可以使用smartpointer来避免管理儿童成员的破坏。

I see one new, but no delete's, nor smart pointers. 我看到一个新的,但没有删除的指针,也没有智能指针。 That means you allocate memory without freeing it accordingly. 这意味着您无需分配内存就可以分配内存。 (At least you did not show us the destructor of Node where that should be done.) (至少您没有向我们展示Node的析构函数应该在哪里进行。)

Apart from that there are several flaws in your code: 除此之外,您的代码还有一些缺陷:

  • Your use of n looks suspicious and it is not clear if what it does is the right thing or simply a bug. 您对n的使用看起来可疑,目前尚不清楚它的作用是正确的还是仅仅是错误。 You may want to at least clarify that by a comment or better by using additional functions and meaningful names. 您可能希望至少通过注释来澄清,或者使用其他功能和有意义的名称来更好地加以说明。
  • You don't stop once you have found a NULL pointer and flood the whole array with new Nodes, meaning you can successfully insert exaclty once 一旦找到NULL指针并用新的Node充满整个数组,您就不会停止,这意味着您可以一次成功插入exaclty
  • You default-construct a node and assign it a value immediately - probably you should write a corresponding constructor. 您默认构造一个节点并立即为其分配一个值-可能您应该编写一个相应的构造器。

Use smart pointers to allocate your memory: 使用智能指针分配内存:

struct Node {
    unique_ptr<Node> children[20]; //consider switching to std::array
    int value;

    // no destructor needed, because unique_ptr takes care of itself    
    Node (int newValue);
    void insert(int valueToInsert);
};


void Node::insert(int valueToInsert) {
    auto freeSpot = //find the point where you want to insert the new node
    if ( /*freeSpot is a valid location*/ )
        *freeSpot = make_unique<Node>(x);
}  

Node::Node(int newValue) 
  : value(newValue)
{}

That would be a first refactoring you could do 那将是您可以做的第一个重构

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

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