如何“完全”删除链表中的所有节点?

时间:2016-03-19 01:22:35

标签: c++ pointers c++11

我很好奇指针和删除指针如何在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到控制台,这意味着头部确实仍然存在。我希望head和它之后的所有其他节点都为null,因此if条件失败,因为将指针设置为null是我在递归函数中做的最后一件事。那么为什么程序会报告头部仍然存在?

编辑:更改列表列表();列表清单;

1 个答案:

答案 0 :(得分:4)

释放了内存,但是nullptr的赋值只影响了传递给函数的指针的副本,而不影响调用者中的原始指针。

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

void deleteList(Node *&node) {

然后node = nullptr;的分配也会影响来电者。

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

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