出于某种原因,在调用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());
}
}
}
};
注意:某些类详细信息已被省略
答案 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
所以你错过了一个复制构造函数和复制赋值运算符(应该进行深层复制)。