2

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

    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;
    }
}

我对如何确保在这种情况下没有内存泄漏感到困惑。如何专门处理节点中的指针?如果我删除 move 它会自动处理这些吗?

4

3 回答 3

1

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

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

如果value绝对需要是一个指针,我会使用 a std::unique_ptr<int>(或者,如果你需要使用 C++ 2003,a std::auto_ptr<int>)。

于 2012-12-10T01:42:12.880 回答
1

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

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

这意味着您的清理功能都没有问题:

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

  • 第二个函数,通过删除列表movemove->prev的每个节点,有可能会删除大多数节点两次,这就是Undefined Behavior

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

于 2012-12-10T01:45:17.060 回答
1

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

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

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

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

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

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

于 2012-12-10T01:49:04.367 回答