0

我是一名计算机科学专业的学生,​​任务是创建动态数据结构、链表。我目前正在研究一个单链表,并已成功构建了添加、删除和转储所有节点数据的功能。

但是,请记住我的“高级编程”讲师说过,为了避免混淆和其他问题,当从列表中删除节点或释放任何对象的内存时,你应该让它发生在它的解构器中。所以我搬家了:

delete[] _del;

效果很好并将其移至节点的解构器:

#include "Node.h"

// Node.cpp

Node::Node(const int &inData, const int &inId)
{
    _id = inId;
    _data = inData;
    nextNode = NULL;
}

// Deconstructor to delete the node when using List.Del()
Node::~Node()
{
    delete[] this;
}

在我的列表中,节点的解构函数通过如下指针调用:

_del->~Node();

这给了我一个断言错误。我假设这是我在节点的解构器中使用“this”?

谢谢你的时间。

4

4 回答 4

2

首先,您不应该直接调用对象析构函数,除非您正在编写分配器并在创建它时使用placement new。其次,delete除非delete[]您也使用过new[]. 最后,delete this是一个坏习惯,但根据标准是合法的。你为什么不打电话delete theNode而不是所有这些?

编辑:解决一些评论/其他问题。

要在堆上分配单个实例,请使用theNode = new Node. 返回的指针必须用 释放delete theNode。调用 new 将分配内存,然后调用Node::Node()构造函数,以便它可以设置它的内部状态。调用 delete 将调用Node::~Node()然后释放分配的内存。析构函数负责清理 Node 使用的任何东西,但不负责清理 Node 本身使用的内存。

要分配节点数组,请使用theNodes = new Node[10];. 你用 删除这些delete[] theNodes。将 new/delete 与 new[]/delete[] 混合是未定义的行为。

Placement new 是一种您希望在已分配的内存中构造对象的方法。在这种情况下,您有直接调用析构函数的唯一充分理由,您想要解构一个对象(也就是让它自己清理)而不释放为其分配的内存。

调用delete this在例如函数中是合法的Suicide(),只要您在调用后不引用“this”或已删除实例的任何成员delete this。这是一种有效的技术,例如在引用计数对象中,但通常被认为是应该避免的,除非你真的需要它。

对您来说正确的解决方案非常简单,您现在调用~Node,只需调用即可delete theNode

于 2011-02-19T09:31:52.760 回答
1
Node::~Node()
{
    delete[] this;
}

未定义的行为。很可能会使您的程序崩溃!

顺便说一下, 和 之间是有区别delete thisdelete[] this。虽然有时delete this可能还可以,但不是,因为永远不能使用. 它不是指向数组的指针。它是一个指向 ONE 对象的指针!delete[] thisthisnew[]

于 2011-02-19T09:26:56.590 回答
1

如何正确地从其解构器中删除对象?

它不是。析构函数清理对象拥有的资源,而不是对象本身。

您应该删除删除的使用,并且分配节点(您的列表类?)最好负责释放它。最简单的方法是在您的列表类中恰好有一个点来分配和添加节点到列表中,并且恰好有一个点可以删除和取消分配节点(提到的 Del 方法)。让列表类的析构函数反复调用 Del 直到列表为空。

于 2011-02-19T09:30:51.633 回答
0

正如先前的答案所暗示的那样,您的解构器是未定义的行为。原因如下:

什么时候

delete[] _del;

被执行。它尝试删除同一个对象,您尝试在其解构函数中删除该对象

delete[] this;

您的课程文本的意思是,如果您想清除与正在删除的对象相关的任何内存,这些内存也应该在该对象的解构器中释放。例如,如果 id 和/或 data 是指针:

Node::~Node()
{
   delete _id;
   delete _data;
}
于 2011-02-19T09:33:18.613 回答