You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++二叉树对象内存释放方法正确性辨析及相关疑问

C++二叉树对象的内存释放困惑及解决方案

初始问题

我对C++二叉树对象的内存释放方法存在困惑,请问以下哪种方式是正确的?

方式1

#include <iostream>
using namespace std;
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

int main()
{
    TreeNode *t1 = new TreeNode(1, new TreeNode(2), new TreeNode(3));
    delete t1;
    return 0;
}

方式2

#include <iostream>
using namespace std;
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

int main()
{
    TreeNode *t1 = new TreeNode(1, new TreeNode(2), new TreeNode(3));
    delete t1->left;
    delete t1->right;
    delete t1;
    return 0;
}

另外,我通过VSCode的反汇编视图查看了delete t1;的地址:

delete t1; // Ox0000000100003dd4 ldur x8, [x29, #-0x10]

执行该行代码时没有任何变化,看不到ldur x8, [x29, #-0x10]相关反馈,不确定内存是否真正被释放,想知道需要学习哪些知识来解决这个问题。

优化后的实现方案

在参考相关建议后,我修改了代码,分别实现了不使用智能指针和使用智能指针的版本:

不使用智能指针的版本

#include <iostream>
using namespace std;
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;

    TreeNode() : val(0), left(nullptr), right(nullptr) {
        cout << "create node " << val << endl;
    }
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {
        cout << "create node " << val << endl;
    }
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {
        cout << "create node " << val << endl;
    }
    ~TreeNode(){
        if (left != nullptr) {
            delete left;
            left = nullptr;
        }
        if (right != nullptr) {
            delete right;
            right = nullptr;
        }
        cout << "delete node " << val << endl;
    }

};

int main()
{
    TreeNode *t = new TreeNode(1, new TreeNode(2), new TreeNode(3));
    delete t;

    return 0;
}

使用智能指针的版本

#include <iostream>
#include <memory>
using namespace std;

struct TreeNode {
    int val;
    unique_ptr<TreeNode> left;
    unique_ptr<TreeNode> right;

    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {
        cout << "create node " << val << endl;
    }
    TreeNode(int x, unique_ptr<TreeNode> l, unique_ptr<TreeNode> r) : val(x), left(move(l)), right(move(r)) {
        cout << "create node " << val << endl;
    }
    ~TreeNode() {
        cout << "delete node " << val << endl;
    }
};

int main() {
    unique_ptr<TreeNode> t1 = make_unique<TreeNode>(1, make_unique<TreeNode>(2), make_unique<TreeNode>(3));

    return 0;
}

关键说明

  • 方式1存在内存泄漏:delete t1仅释放根节点内存,左右子节点的内存不会被自动回收,因为默认析构函数不会递归处理子节点指针。
  • 方式2虽能释放所有节点,但手动释放的方式在复杂树结构下极易遗漏或出错,代码冗余度高。
  • 非智能指针优化版通过自定义析构函数,递归释放左右子节点,确保所有节点内存被回收,同时通过日志输出可直观验证释放过程。
  • 智能指针版利用unique_ptr的自动析构特性,无需手动调用delete,当unique_ptr生命周期结束时,会自动触发对象析构,进而递归释放子节点的unique_ptr管理的内存,从根源避免内存泄漏。
  • 若要彻底解决内存释放验证及原理问题,需要学习:C++动态内存分配与释放规则、析构函数工作机制、智能指针的使用场景与原理、内存泄漏检测工具(如Valgrind)、汇编层面的内存操作逻辑。

内容的提问来源于stack exchange,提问作者rann rann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 16:55:34