这个单链列表析构函数如何引起无限循环?

时间:2018-12-14 09:09:43

标签: c++ linked-list destructor singly-linked-list

我使用struct编写了一个单链列表实现。它不是管理列表上的操作的外部类的一部分。相反,所有操作都直接由节点处理。

我知道,如果结构定义是类的一部分,例如ListManager,则在ListManager实例上调用析构函数将只需要遍历该类管理的链接列表并删除每个Node。

但是,由于此链表不是外部类的一部分,而是管理所有操作本身,因此我对如何编写析构函数有些困惑。

版本1运作良好,它是一个遍历列表的递归调用,释放并释放了与每个Node关联的内存。

版本2导致无限循环。我不明白为什么,因为这是我为管理Node链表的容器类实现析构函数的一种方式。

版本3运作良好,但过于冗长。

我使用valgrind和python导师运行了这三个版本,以检查是否存在泄漏和其他问题。

感谢您帮助解释为什么版本2无法正常工作以及为什么以这种方式实现析构函数是不正确的!

结构链接列表

#include <iostream> 
#include <string> 
using namespace std; 

struct Node
{   
    int id; 
    Node* next; 
    Node(int newId = 0, Node* newNext = NULL)
    : id(newId), next(newNext) { } 
};

析构函数版本1

~Node()
{
    if (next != NULL)
        delete next; 
}

析构函数版本2

~Node()
{
    Node* lead = this; 
    Node* follow = this;

    while (follow != NULL)
    {
        lead = lead->next; 
        delete follow; 
        follow = lead; 
    }
}

析构函数版本3

~Node()
{
    Node* lead = this; 
    Node* follow = this;

    if (follow != NULL)
    {
        lead = lead->next; 
        delete follow; 
        follow = lead; 
    }
}

主要

int main()
{
    Node* head = NULL; 
    head = new Node(23, head); 
    head = new Node(54, head); 
    head = new Node(81, head);
    head = new Node(92, head); 
    delete head;     
    return 0; 
}

2 个答案:

答案 0 :(得分:3)

在版本2中,您编写了一个循环,该循环通过遍历列表并删除每个元素来在一个析构函数调用中清除整个列表。但是,发生的情况不是您只有一个析构函数调用。每次删除元素时,都会再次调用析构函数。

因此最后,delete follow转换为delete this(因为follow = this;)用于第一次调用。然后,这将导致再次调用第一个节点的析构函数,从而导致无限循环。

以下节点将被破坏多次,从而导致不确定的行为,但由于该无限循环,它甚至没有到达那里。

答案 1 :(得分:1)

您只需要每个Node即可删除(最多)一个其他{em> {em> ),以最终删除所有节点。重新分配本地指针不会影响列表的结构。

2和3均为Node,在销毁者中,最好时机是可疑的,加上一些无关的仪式。它们都是 不确定的行为,(至少)两次删除同一对象。

您的第一次尝试已经结束。

使用混乱的指针类型来代替自己,而不必使用指针值,例如delete this

std::unique_ptr