我正在编写一个链表,我想要一个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;
}
这是否可以接受,特别是在这种背景下?
答案 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
是合理的,可以解除分配当前对象,但不能从析构函数中释放。