【问题标题】:How can you avoid leaking memory when removing from a doubly-linked list?从双向链表中删除时如何避免内存泄漏?
【发布时间】:2012-12-09 10:37:47
【问题描述】:

假设我有一个双向链表,例如

class list
{
    /*...*/

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

    node* first; //NULL if none
    node* last; //NULL if none

    /*...*/
}

如果我想写一个函数来删除第一个节点并返回一个指向其值的指针,这个实现会泄漏内存吗?

int* returnFrontValue()
{
   if(list_is_Empty())
        throw -1;
   else
   {
        node* v = first;
        int* returnMe = v->value;

        first = first->next;
        if(!first)
            last = NULL;

        delete v;
        first->prev = NULL;

        return returnMe;
   }
}

我很好奇这个实现是否会泄漏内存,因为returnMe 指向一个动态分配的 int。使用int returnMe = *(v->value); 并在最后返回&returnMe; 会更好吗?

我必须在delete v; 之前明确地delete v->value; 吗?当您有各种指针时,我对删除内存的工作方式感到困惑。

【问题讨论】:

  • 返回一个局部变量的地址?绝对不会更好。
  • 为什么每个节点都有一个指向动态分配的int的指针,而不是简单的int成员?
  • @interjay 如果是会员,delete v 会销毁它
  • @Evgeni 所以?在删除之前复制它。
  • @jalf 是的,按值返回将是一个解决方案。

标签: c++ linked-list


【解决方案1】:

我们看不到int 是如何分配的,但我相信它是动态分配的(作为与您删除的节点分开的分配)。

在那种情况下不,你还没有泄露任何东西,但你是在诱惑命运。这不是泄漏,因为指向int 的指针仍然存在,所以它仍然可以被删除。但现在责任在于调用者。如果我调用returnFrontCaller,我会得到一个指向一个值的指针,然后我必须在完成后调用delete

这不是很直观。一般new/delete调用应该在同一个地方匹配。如果我打电话给new,我也会打电话给delete。如果new 调用发生在其他地方,我不会指望调用delete 是我的责任。

但是为什么值在allWhy do you store anint*instead of anint`处是动态分配的呢?为什么函数返回一个指向 int 的指针,而不是它的副本?

如果您进行了更改,则无需进行内存管理。调用者会得到一个 int,而不必担心“谁调用了delete”。

或者,您可以使用智能指针类来包装它,并处理内存管理。

【讨论】:

  • 那么在这个例子中,当我删除一个节点时会发生什么?它包含三个指针,我必须单独删除它们吗?
  • 当您删除一个节点时,如前所述,指向 int* 的指针会悬空。如果调用者丢失它并且没有删除,则存在泄漏。其他指针指向不会被此删除操作删除的现有节点,因此不需要(也不应该通过此删除调用)删除它们。
  • 当你删除一个节点时,首先调用类的析构函数,然后节点类的每个成员都调用它的析构函数。对于原始指针,这没有任何影响(特别是,它不会删除指针指向的任何内容)。
猜你喜欢
  • 2020-09-06
  • 1970-01-01
  • 1970-01-01
  • 2016-06-11
  • 2012-11-30
  • 1970-01-01
  • 2016-09-02
  • 1970-01-01
相关资源
最近更新 更多