指向其值的双链接列表的析构函数

Destructor for a doubly-linked list that points to its value

本文关键字:链接 列表 析构函数      更新时间:2023-10-16

假设我有一个由类定义的双链表

class list
{
/*...*/
private:
struct node
{
node* prev;
node* next;
int* value;
}
node* first; //NULL if none
node* last; //NULL if none
/*...*/
}

如果我想为这个列表创建一个析构函数,我是否必须显式删除该值?

list::~list()
{
node* move = first;
while(first)
{
first = move->next;
delete move;
move = first;
}
}

以上方法能确保没有内存泄漏吗?或者我必须做什么:

list::~list()
{
node* move = first;
while(first)
{
first = move->next;
delete move->value;
delete move->prev;
delete move;
move = first;
}
}

在这种情况下,我很困惑如何确保没有内存泄露。如何具体处理节点中的指针?如果我删除移动,它会自动处理这些吗?

您需要将每个new与恰好一个delete配对。也就是说,您可能不希望delete prev(此节点已被删除),但希望delete value。好吧,我会把value嵌入到对象中,而不是指向它:

struct node
{
node* prev;
node* next;
int   value;
};

如果value绝对需要作为指针,我会使用std::unique_ptr<int>(或者,如果您需要使用C++2003,则使用std::auto_ptr<int>)。

对于每个成功的new表达式,在该对象上精确调用delete一次。

对于每个成功的new[]表达式,在该对象上精确调用delete[]一次。

这意味着你的清理功能都不正常:

  • 第一个函数忘记了deletevalue,这意味着内存泄漏。

  • 第二个函数通过删除列表中每个节点的movemove->prev,有可能删除大多数节点两次,即未定义的行为

为了避免第一个函数的内存泄漏,只需直接存储整数,而不是动态分配。

是否必须删除value成员的内存指针-只有您自己知道。这是一个内存所有权的问题,一个设计的问题。如果列表拥有value成员指向的数据内存,则必须在列表析构函数中删除它(即,当列表消亡时,它所拥有的数据也随之消亡)。

如果列表没有value内存,那么您不应该删除它。同样,只有您才能回答您的列表是否应该拥有value内存的问题。这是你的意图问题。

现在,对于node对象所占用的内存,它显然是列表所拥有的,因此必须在析构函数中小心地将其释放。你的去cructor的第一个版本几乎是正确的(第二个版本根本没有意义),只是它是以一种稍微模糊的方式编写的。这应该是足够的

list::~list()
{
while (first)
{
node *move = first;
first = first->next;
delete move;
}
}

(同样,如果你必须删除value,那么delete move->value应该在delete move之前添加到你的周期中。)

附言:一旦你了解了这一点,你可能想研究各种智能指针类,它们允许你显式地表达内存所有权关系,从而让编译器知道它们。如果使用得当,它们将使内存管理几乎自动化。