节点和二叉树构造函数和析构函数分段

Node and Binary Tree Constructor and Destructor Segfaulting

本文关键字:分段 析构函数 二叉树 节点 构造函数      更新时间:2023-10-16

我以前在这里看到过这个问题,特别是

通用二进制树节点析构函数问题和二进制搜索树析构函数

但到目前为止,我得到的答案是在构造函数中将Node指针设置为NULL。这是我的Node和Tree的构造函数和析构函数的代码。

template <class Type>
class Node {
protected:
    Type data;
public:
    Node<Type>(Type data) { this->data = data; }
};

二叉树节点继承自上面的节点(我知道不使用继承,只使用BinaryTreeNode直接处理数据会更容易,但我选择这样做是因为我正在练习)

BinaryTreeNode类:

template <class Type>
class BinaryTreeNode: public Node<Type> {
protected:
BinaryTreeNode<Type> *left;
BinaryTreeNode<Type> *right;
BinaryTreeNode<Type> *parent;
public:
BinaryTreeNode<Type>(Type data) : Node<Type>(data) {
    this->left = NULL;
    this->right = NULL;
    this->parent = NULL;
}
~BinaryTreeNode<Type>() {
    delete left;
    delete right;
    delete parent;
}
};

对于树:

template <class Type, template <class> class NodeType = BinaryTreeNode>
class BinaryTree {
protected:
    int size;
    NodeType<Type> *root;
public:
    ~BinaryTree<Type, NodeType>() {
        delete root;
    }
    BinaryTree<Type, NodeType>() {
        this->size = 0;
        this->root = NULL;
    }
};

现在,我主要做以下工作:

BinaryTree<int> *bt = new BinaryTree<int>();
bt->insert(100);
bt->insert(50);
bt->insert(101);

以上作品,到目前为止还不错。

插入方法/函数用于创建NEW节点。然后我尝试使用以下每一个(一个接一个),它们都会导致segfault(核心转储):

delete bt->getRoot();

这导致了segfault。然后我尝试了

delete bt->getRoot()->getRight();

再次出现segfault。所以上次我试过

delete bt;

静止分段

我原本以为其他节点无法访问会导致内存泄漏(我用valgrind运行它),但令我惊讶的是,valgrind崩溃了,gcc和clang甚至没有打印出任何警告,即使使用-Wall。我需要关于如何正确地做这件事的建议。提前谢谢。

这会把搞砸的

~BinaryTreeNode<Type>() {
    delete left;
    delete right;
    delete parent;
}

删除左边,然后删除右边。看起来不错。但由于下一行而失败
现在删除父对象。然后调用父级析构函数来删除左、右和父级。因此,通过删除你的父母,你会对自己调用delete,但你已经处于删除过程中,因为其他人试图调用delete。这并不是你进入一个永远不会退出的递归循环的唯一问题。

尝试:

~BinaryTreeNode<Type>() {
    delete left;
    delete right;
}

父母应该删除他们的孩子,因为他们拥有自己的孩子
但孩子不应该删除那里的父母(因为孩子不拥有父母)。

如果您使用C++技术而不是C技术,这将是显而易见的(并且是自动完成的)。查找std::unique_ptr<>

PS。您的对象也存在根本缺陷,因为您没有实现三(C++11中的五)规则。

如果您的调用顺序是

delete bt->getRoot();
delete bt->getRoot()->getRight();
delete bt;

然后,当您删除一个节点,然后使用同一节点本身调用一个方法时,它将产生一个问题。订单应为

delete bt->getRoot()->getRight();
delete bt->getRoot();
delete bt;

移除delete bt->getRoot()->getRight();(用于更多内存泄漏:)或将其移动到delete bt->getRoot(); 之前的行