【问题标题】:Node and Binary Tree Constructor and Destructor Segfaulting节点和二叉树构造函数和析构函数段错误
【发布时间】:2013-08-05 17:12:08
【问题描述】:

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

Generic binary tree node destructor issueBinary Search Tree Destructor 除其他外

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

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);

以上工作,到目前为止一切顺利。

插入方法/函数是创建新节点的地方。然后我尝试使用以下每个(一个一个),它们都导致段错误(核心转储):

delete bt->getRoot();

这导致了段错误。然后我尝试了

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

再次出现段错误。所以最后我尝试了

delete bt;

还是段错误

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

【问题讨论】:

    标签: c++ data-structures constructor binary-tree destructor


    【解决方案1】:

    这会搞砸你的

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

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

    试试:

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

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

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

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

    【讨论】:

    • 哦,我明白了。这就是它所需要的。它现在工作。谢谢。我在 C++ 方面还没有那么丰富的经验,这就是为什么我正在考虑删除类中的每个指针,甚至是父指针。
    • @MarcLee:您应该手动删除指针。使用智能指针。我建议你停止这样做。它只会导致难以改掉的坏习惯(这是 C)。学习 C++ 方法并使用智能指针。他们会自动为你调用 delete。
    【解决方案2】:

    如果你的调用顺序是

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

    然后它会在您删除节点然后使用同一节点本身调用方法时产生问题。顺序应该是

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

    【讨论】:

    • 我一次尝试了这些东西。每个都导致一个段错误。当我尝试只向树中插入一个节点时,使用 delete bt 不会导致段错误。
    • 我们想看看 insert() 方法。您还确定 insert() 工作正常吗?你检查了吗?
    • 好的,我会发布它。不确定它在内存分配方面是否正确,但在构造树方面,它工作正常。
    【解决方案3】:

    要么删除delete bt-&gt;getRoot()-&gt;getRight();(更多内存泄漏:))或将其移至delete bt-&gt;getRoot();之前的行

    【讨论】:

    • 我认为我提到它的方式令人困惑。正如我上面写的那样,我单独尝试了这些行,而不是完全(按顺序)尝试了这些行。为了更清晰,我编辑了帖子。基本上,我创建了一个高度为 1 的树,一个父节点(根节点)和两个子节点(左右)。删除任何节点都会导致段错误。
    猜你喜欢
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 1970-01-01
    • 2011-12-22
    • 1970-01-01
    • 1970-01-01
    • 2013-07-07
    • 1970-01-01
    相关资源
    最近更新 更多