删除关键字时抛出访问冲突异常

时间:2014-05-23 19:45:40

标签: c++ pointers

出于某种原因,在调用AddToBinarySearchTree之后,会从~BinarySearchTreeNode<T>析构函数中抛出异常。我认为这可能会发生,因为在删除树之前删除Node本身 - 但我不认为是这种情况。

为什么调用delete m_left;会抛出以下异常?

  

访问冲突读取位置0xFEEEFEF2

int _tmain(int argc, _TCHAR* argv[])
{
    void AddToBinarySearchTree(BinarySearchTree<T> bst, T value) {
        bst.Add(value);
    }

    void MyMethod() {
        BinarySearchTree<int> bstStack;
        bstStack.Add(5)
        // the exception is thrown after this line of code executes
        AddToBinarySearchTree(bstStack, 1000);
    }
}

// BinarySearchTreeNode<T>
template <typename>
BinarySearchTreeNode {
public:
    BinarySearchTreeNode<T>::~BinarySearchTreeNode() {
        // executing the following line of code throws the exception
        delete this->m_left;
        this->m_left = NULL;
        delete this->m_right;
        this->m_right = NULL;
    }
};

// BinarySearchTree<T>
template <typename T>
class BinarySearchTree {
    BinarySearchTree<T>::~BinarySearchTree() {
        delete m_head;
        m_head = NULL;
    }

    void BinarySearchTree<T>::Add(T value) {
        Add(new BinarySearchTreeNode<T>(value));
    }

    AddRecursive(BinarySearchTreeNode<T>* node, BinarySearchTreeNode<T>* parentNode) {
        if (node->GetValue() < parentNode->GetValue()) {
            if (!parentNode->GetLeft()) {
                parentNode->SetLeft(node);
            }
            else {
                this->AddRecursive(node, parentNode->GetLeft());
            }
        }
        else if (node->GetValue() > parentNode->GetValue()) {
            if (!parentNode->GetRight()){
                parentNode->SetRight(node);
            }
            else {
                this->AddRecursive(node, parentNode->GetRight());
            }
        }
    }
};

注意:某些类详细信息已被省略

2 个答案:

答案 0 :(得分:3)

&#34;访问违规&#34;在析构函数中意味着指针无效。通常已经调用了析构函数。

&#34;读取位置0xFEEEFEF2&#34;告诉我们更多。也就是说,当调试运行时释放内存时,它会使用模式0xFEEEFEEE(看起来很熟悉?)填充它,这肯定了我们相信包含指针的对象已被释放。 (更多信息:https://stackoverflow.com/a/127404/845092

带有指针的对象是BinarySearchTreeNode,这意味着该节点已被释放,您可以再次释放它。至于即将发生的,你必须检查你没有粘贴的代码。我要检查的第一件事是复制构造函数和复制赋值运算符。

<小时/> Curg注意到AddToBinarySearchTree中缺少的参考文献。这告诉我它是你的复制构造函数,可能是你没有制作一个。当您致电AddToBinarySearchTree时,该功能会在堆栈上创建一个全新的BinarySearchTree,可能会引用相同的节点,然后您将添加到副本中。然后当函数结束时,副本被销毁,释放节点。然后MyMethod结束,它试图销毁原始版本,它试图再次释放这些相同的节点。

答案 1 :(得分:1)

我决定把这个问题写进去。正如Curg所说,当你通过值而不是引用传递给“AddToBinarySearchTree”时会出现问题。

但这不是你的错误。这就是你的错误出现的时候。

看起来是因为当您调用该函数时,您会创建该类的浅表副本,包括所有指针值。然后当函数结束时,该实例超出范围。它清理自己(正确地)在它复制的实例中留下悬空指针。当您尝试清理它时,您会收到错误。编译器将FEEEEFEEE放入已释放的内存中。

错误在于你没有遵循三个规则,即(维基百科):

一个类定义了下面的一个,它应该明确地定义所有三个:

destructor
copy constructor
copy assignment operator

所以你错过了一个复制构造函数和复制赋值运算符(应该进行深层复制)。