是否可以使用“删除此项”删除当前对象?

时间:2009-08-11 01:26:38

标签: c++ linked-list this destructor self-destruction

我正在编写一个链表,我想要一个struct的析构函数(一个Node结构)来简单地删除它自己,并且没有任何副作用。我希望我的list的析构函数迭代地调用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::~Node
{
   delete this;
}

这是否可以接受,特别是在这种背景下?

8 个答案:

答案 0 :(得分: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;
  }
}

答案 1 :(得分:4)

不,你不应该从析构函数中delete this。析构函数因为删除语句而被调用(或超出范围),这很可能会导致某种崩溃。

在DoublyLinkedList目标中也存在一些问题。一,删除临时删除后访问temp。其次,代码实际上不会删除链表中的最后一个元素。

答案 2 :(得分:4)

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

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

如果要递归删除结构,则需要以下内容:

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

Node::~Node
{
   if(this->next() != NULL) delete this->next();
}

答案 3 :(得分:2)

其他事情:我真的,真的希望这是分配给你的功课,以便了解双重链表。否则,没有理由使用它代替std::list。除此之外:

不,dtor中的delete this总是错误的,因为当this处于被删除状态时会调用dtor。

此外,还有

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

偶然可能会有效,这肯定是错误的,因为在您尝试访问temp->next()时,temp已被删除,因此您应该在其上调用成员函数。这样做会调用所谓的“未定义行为”。 (简而言之:它可能会做你想要的,但它也可能总是或偶尔失败,或者只有在星期五,13日与新月相撞时。它也会在你身上引用非常讨厌的鼻子恶魔。)

请注意,您可以通过删除节点的dtor中的下一个节点来解决这两个问题:

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

这样,您的列表也变得非常简单:

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

对我而言,这似乎是dors的发明,因此,除了现在没有人应该编写自己的链表类型这一事实,对我来说这似乎是 C ++解决方案给你问题。

答案 4 :(得分:1)

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

答案 5 :(得分:0)

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

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

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

答案 6 :(得分:0)

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

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

顺便说一句,子类化也会发生同样的事情 - 如果你有A类,B类:public A,那么当你做一个新的B()时,A构造函数首先执行,然后执行B的构造函数;在破坏时,B的析构函数首先执行,然后是A的。我很确定你不必担心这个问题,但C ++会为你解决这个问题。所以不要试图找出一种在超类上调用delete的方法。

答案 7 :(得分:0)

两者都不应该完成。

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

将导致未定义的行为 - 您不允许访问已返回堆的内存。相反它应该是:

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

调用delete this将导致所谓的double free,这也会导致未定义的行为。析构函数应该只为指针成员变量调用delete,而不是this。从其他方法调用delete this是合理的,可以解除分配当前对象,但不能从析构函数中释放。