在什么情况下 delete 运算符会抛出错误?

In what context does the delete operator throw an error?

在我的链表实现中,删除内部 class Node 实例的辅助函数 deleteNode(Node*) 抛出运行时错误,由 "triggering a breakpoint" 在VS 2015 中的本地 Windows 调试器。我很小心地匹配我的 newdelete 运算符。 scope/reference 是否起到了我没有意识到的作用?

即使clear()出现逻辑错误,deleteNode()通过nullptr,删除nullptr也不应该抛错,然后赋值nullptr 对自己好吗?该删除有什么问题?

class LinkedList {
public:
    LinkedList() : head(nullptr) {}
    ~LinkedList() { clear(); }

    void push_front() {
        head = createNode(head);
    }

    void clear() {
        Node* current_node = head;
        while (current_node != nullptr) {
            Node* next_node = current_node->next; // buffer
            deleteNode(current_node);
            current_node = next_node;
        }
    }

private:    
    struct Node {
        Node(Node* next)
            : next(next) {}
        Node* next;
    };
    Node* head;
    Node* createNode(Node* next) {
        return new Node(next);
    }
    void deleteNode(Node*& toDelete) {
        delete toDelete; // ***VS 2015 puts breakpoint here***
        toDelete = nullptr;
    }
};

int main() {
    auto A = LinkedList();
    A.push_front();
    A.clear();
    return 0;
}

我删除了所有与错误无关的属性和方法。这个伪代码仍然抛出同样的错误。

In what context does the delete operator throw an error?

一个delete表达式可以抛出,如果析构函数本身抛出,或者一个子对象的析构函数。但是你应该避免使用析构函数。

如果您尝试删除未指向有效对象的指针,delete 表达式也可能具有未定义的行为。 nullptr 是一个例外,可以安全删除。意外删除无效指针的典型原因是试图删除相同的指针值两次,或者忘记初始化内存。未定义的行为可能导致任何结果,包括抛出错误。

What is the issue with that delete?

您正在删除同一个指针两次。您可以通过检查调试器中的值来验证这一点。

问题出在您的 clear() 函数中。你看,你 认为 由于你编写 deleteNode 函数的方式,你所有的节点都将 nullptrclear 之后。不幸的是,事实并非如此。您将 head 复制到 current_node,并且 head 的副本(即 current_node)在被删除时变成 nullptr,但 head 保持非空.稍后析构函数尝试再次删除它。在已释放的内存上调用 delete 会导致未定义的行为。

要修复,请添加

 head = nullptr;

在你清除函数的最后