【踩坑记录】C++ 递归delete释放内存以及使用的时候遇到的问题或者使用析构函数释放内存

一、使用递归释放空间

前段时间写了一段代码,其中包含一个结构体:

struct Node {
    int value;
    Node * nexts[26];

    Node() {
        value = 0;
        for (auto& i : nexts) {
            i = nullptr;
        }
    }

};

结构体中包含一个int类型的值和一个Node*的指针数组,其中数组中的指针初始化为nullptr。当数组中的指针需要指向另一个Node时,使用new分配内存。所以当我们需要释放内存空间的时候,就需要使用delete来释放。

想法是,通过递归遍历到最后一层节点,然后依次从后往前释放内存。代码如下:

void delete_node_re(Node * node){
    if (node == nullptr) {
        return;
    }
    for (int i = 0; i < 26; ++i) {
        delete_node_re(node->nexts[i]);
    }
    delete node;
    node = nullptr;
}

但是当我调试的时候发现,指针并没有置空,还是指向了一个地址。经过检查,代码逻辑上没有问题,也能够成功将内存释放掉,唯一有一点问题的地方在于下面这一句代码。

node = nullptr;

我们知道,delete只是释放指针所指向的空间,但是并不会删除指针,所以我们在delete之后需要手动将指针置为空指针。但是对于该函数而言,这样子将指针置为空指针是无效的。因为函数传递的是形参,并不会影响函数体外传入的参数。为了验证所想,简单写了一个函数。

void test(int * p) {
    * p = 1;
    cout<<"test &p:"<<&p<

输出:

test &p:0xf84dbffcf0
test p:0xf84dbffd14
test *p:1
after null p:0
main &p:0xf84dbffd18
main p:0xf84dbffd14
main *p:1

可以看到,两个p的地址不是同一个,但是他们指向同一块内存。当函数中的p被置为nullptr时,函数外的p不受影响。所以递归函数应改为:

void delete_node_re(Node * node){
    if (node == nullptr) {
        return;
    }
    for (int i = 0; i < 26; ++i) {
        delete_node_re(node->nexts[i]);
        node->nexts[i] = nullptr;
    }
    delete node;
}

同时,调用的时候应该是这样调用:

delete_node_re(node);//node是Node结构体指针
node = nullptr;

二、定义析构函数释放内存

除了使用递归来释放上述的内存外,还可以使用析构函数来释放内存。结构体代码如下:

struct Node {
    int value;
    Node * nexts[26];

    Node() {
        value = 0;
        for (auto& i : nexts) {
            i = nullptr;
        }
    }

    ~Node() {
        for (int i = 0; i < 26; ++i) {
            delete nexts[i];
            nexts[i] = nullptr;
        }
    }
};

调用的时候只需:

delete node;
node = nullptr;

比上述的递归简单了不少,这里需要注意的是不要对同一内存进行两次delete。

你可能感兴趣的:(C++踩坑记录,C/C++,c++,数据结构,算法)