7

我正在编写一个链表,我希望一个结构的析构函数(一个节点结构)简单地删除自己,并且没有任何副作用。我希望我的列表的析构函数迭代地调用自身的 Node 析构函数(临时存储下一个节点),如下所示:

//my list class has first and last pointers
//and my nodes each have a pointer to the previous and next
//node
DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();

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

所以这将是我的节点析构函数:

Node::~Node
{
   delete this;
}

这是否可以接受,尤其是在这种情况下?

4

8 回答 8

17

如果 Node 析构函数被调用,那么它已经在被删除的过程中。所以在你的 Node 析构函数中删除是没有意义的。

这也是错误的:

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

相反,您应该将 temp->next() 放入临时变量中。否则,您正在访问已删除的内存。

所以更像这样:

DoublyLinkedList::~DoublyLinkedList
{
  Node *temp = first();
  while (temp != NULL)
  {
       Node *temp2 = temp->next();
       delete temp;
       temp = temp2;
  }
}
于 2009-08-11T01:34:06.290 回答
4

不,您不应该delete this使用析构函数。由于删除语句(或超出范围)而调用了析构函数,这很可能导致某种崩溃。

在 DoublyLinkedList 析构函数中也存在一些问题。一,你删除 temp 然后在它被删除后访问 temp。其次,代码实际上不会删除链表中的最后一个元素。

于 2009-08-11T01:37:46.210 回答
4

目前,您的代码会导致访问冲突,因为以下第二行清楚地访问了释放的内存:

delete temp;
temp = temp->next();

如果你想递归地删除结构,你需要这样的东西:

DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();
    delete temp;
}

Node::~Node
{
   if(this->next() != NULL) delete this->next();
}
于 2009-08-11T01:40:31.650 回答
2

Before anything else: I really, really hope this is homework assigned to you in order to understand a doubly linked list. Otherwise there is no reason to use this instead of std::list. With this out of the way:

No, delete this in a dtor is always wrong, as the dtor is called when this is in the state of being deleted.

Also, while

delete temp;
temp = temp->next();

incidentally might work, it's certainly wrong, since, where you attempt to access temp->next(), temp is already deleted, so you should call a member function on it. Doing so invokes so-called "undefined behavior". (In short: It might do what you want, but it might just as well fail always or sporadically or only when Friday, 13th, collides with new moon. It migh also invoke very nasty nasal demons on you.)

Note that you could solve both problems by deleting the next node in your node's dtor:

Node::~Node()
{
   delete next();
}

That way, your list dtor becomes very easy, too:

DoublyLinkedList::~DoublyLinkedList()
{
    delete first();
}

To me, this seems what dtors were invented for, so, except for the fact that nobody should write their own linked list types anymore nowadays, to me this seem to be the C++ solution to your problem.

于 2009-08-11T08:57:15.647 回答
1

删除这个;将调用当前对象的析构函数。在这种情况下,如果你打电话删除这个;在析构函数中,析构函数将被无限调用直到崩溃。

于 2009-08-11T01:37:46.880 回答
0

Both should never be done.

This

DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();
    while (temp->next() != NULL)
    {
        delete temp;
        temp = temp->next();
    }
}

will cause undefined behaviour - you're not allowed to access memory that you've returned to the heap. Instead it shoud be:

DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();
    while( temp != NULL)
    {
        Node* next = temp->next();
        delete temp;
        temp = next;
    }
}

Calling delete this will lead to so-called double free which will also cause undefined behaviour. The destructor should only call delete for pointer member variables, never for this. Calling delete this is reasonable from other methods to deallocate the current object, but not from the destructor.

于 2009-08-11T09:05:00.343 回答
0

上面的代码将调用 Node::~Node() 两次。(在“删除临时”和 Node::~Node() 中)

Node::~Node() 不应该调用“delete this”(否则你的程序会崩溃)

附言。代码中的 while 循环将不起作用。它将取消引用无效指针。你应该先复制 temp->next 的值,然后销毁 temp 指针。

于 2009-08-11T01:37:18.847 回答
0

一般来说,析构函数应该只担心删除(或者如果您使用 C 或 malloc,则释放)专门为您的对象分配的任何内存。删除指向对象的指针将始终由操作系统管理,您不必担心该部分的任何事情。

值得记住的一件事是,在构造时,首先创建对象(当控制流进入构造函数的主体时),然后是内部的对象;对于破坏,你必须反过来做,因为如果你先删除外部对象,你将无法访问内部指针来删除它们。相反,您使用析构函数删除内部对象,然后当控制流脱离析构函数时,操作系统会管理实际的内存释放。

顺便说一句,子类化也会发生同样的事情——如果你有类 A 和类 B : public A,那么当你执行 new B() 时,首先执行 A 构造函数,然后执行 B 的构造函数;在销毁时,B 的析构函数首先执行,然后是 A 的。不过,我相当确定您不必担心这一点——C++ 会为您处理好它。所以不要试图找出在超类上调用 delete 的方法。

于 2009-08-11T01:44:30.287 回答