我有以下代码:
class Node {
public:
int data;
Node* parent;
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
public:
explicit Node(int d) : data(d),
parent(nullptr),
left(nullptr),
right(nullptr) { }
/*
Some functions
*/
};
class dt {
private:
Node* root;
private:
void add_helper(Node* parent, Node* node);
/*
Some helper functions
*/
public:
dt() : root(nullptr) {}
~dt() {
delete root;
}
/*
Some functions
*/
void add(int data);
};
void dt::add(int data) {
if(!root) {
root = new Node(data); // 1: memory leak
return;
}
Node* node = new Node(data); // 2: memory leak
add_helper(root, node);
}
当我扫描此代码以查找内存泄漏时 Dr。Dr.内存在以上注释中提到的行上显示错误。但是它们真的是内存泄漏吗? dt 具有要删除 root 指针的析构函数。当析构函数将开始删除 root 节点时,它将递归进行并删除其所有子代。还是有其他事情发生?
答案 0 :(得分:1)
这些行真的引起内存泄漏吗?
在行Node* node = new Node(data)
上分配的内存可能会泄漏。至少该示例没有显示指针将在何处删除。所有权可能会在add_helper
内转移,但已从示例中排除。
我不熟悉Memory博士,但我会假设它报告泄漏的内存分配到的位置;不是泄漏的地方。
此外,如果您复制dt
实例,则程序的行为将是不确定的,因为原始副本和副本都将尝试删除复制的指针。
要修复潜在的内存泄漏和潜在的UB,请使用唯一的指针。就像您使用Node
一样。
我不能将unqiue_ptr用作root,因为有多个指向同一Node的指针。
通过在析构函数中执行delete root;
,您的类将承担指针的唯一所有权。如果这个假设是正确的,那么使用唯一指针没有问题。如果假设不正确,则析构函数可能会导致不确定的行为。用它代替唯一的指针不是解决方案。您可能需要改用共享指针。
最后,除非您的树是平衡的,否则隐式递归析构函数具有线性增加的最坏情况递归深度,这很容易导致堆栈溢出。您应该平衡树(例如使用redback或AVL增强)或使用迭代算法销毁子树。