如何"completely"删除链表中的所有节点?

How to "completely" delete all nodes in a linked list?

本文关键字:节点 completely 删除 链表 如何      更新时间:2023-10-16

我对指针和删除指针在C++中的工作原理感到好奇,所以我设置了一个实验。我做了一个非常简单的单链表和以下递归函数,用于删除列表中的所有节点:

void deleteList(Node *node) {
    if (!node)
        return;
    deleteList(node->next);
    cout << "deleting node " << node->data << endl;
    delete node;
    node = nullptr;
}

我想这成功删除了列表中的所有节点。但是,在main中调用此函数后,我检查头节点是否仍然存在:

List list;
// appending a bunch of numbers to the list...
list.deleteList(list.head);
if (list.head) 
    cout << true;

这会将 1 打印到控制台,这意味着头部确实仍然存在。我希望头部和它之后的所有其他节点都是空的,因此 if 条件失败,因为将指针设置为 null 是我在递归函数中做的最后一件事。那么,为什么程序报告头部仍然存在呢?

编辑:更改列表列表(); 到列表列表;

您释放了内存,但分配给nullptr仅影响传递给函数的指针副本,而不会影响调用方中的原始指针。

如果将函数声明为通过引用接收指针:

void deleteList(Node *&node) {

然后,node = nullptr;的分配也会影响调用方。

请注意,由于您标记了此 C++11,因此通常将链表定义为正向的一系列 std::unique_ptr<Node> s(如果它是双向的,则为反向的原始指针以避免引用周期),因此您可以避免需要特殊的删除器函数,只需将头部指针设置为 nullptr 并让C++做级联删除的工作。

编辑:让std::unique_ptr做这项工作存在一个缺陷;正如评论中指出的那样,这意味着列表大小实际上受到堆栈的限制,当您删除它们时,太大的列表会导致堆栈溢出。因此,逐个显式清除(最简单的方法是正确实现弹出,并且清除只是弹出,直到head通过popleft方法转换为nullptr)会更安全。我把原来的建议留给后人,所以这个解释是有道理的。