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
相关产品推荐
相关产品推荐

