我的代码中是否有内存泄漏?

时间:2015-08-06 18:51:52

标签: c++ memory memory-management memory-leaks

我在IntList实现中向push_back个节点提供了一小段代码。我的问题是*pnode是否导致内存泄漏,或者我是否需要在最后删除它。

void IntList::push_back(int data){
    if (first){
        IntNode *pNode = first;
        while(pNode->next!=0){pNode = pNode->next;}
        pNode->next = new IntNode(data);
    } else
        first = new IntNode(data);
}

5 个答案:

答案 0 :(得分:1)

不,您不需要在delete上致电pNode。您只能在使用delete创建的内容上调用new。使用现在的代码pNode是一个堆栈对象,当它在函数末尾超出范围时将自动销毁。

答案 1 :(得分:0)

您必须删除最终使用new创建的IntNode,可能是在容器的析构函数和pop_back函数中。 pNode本身(指针)在堆栈上分配,而不是new,因此不需要删除。

答案 2 :(得分:0)

您不需要删除pNode。而且,在这种特殊情况下你无法做到这一点。 在使用new创建内容后,您必须delete一次 - 一旦您永远不会使用它。 使用delete删除对象后,尝试读取其内容为undefined behavior。指针通常是中产生错误最多的部分之一,所以你试图更好地理解它是件好事。

你可以用这种方式想象自己:你可以用new买房子(房子是一块记忆)。它会返回你的地址。它现在是你的房子,可以随心所欲。您也可以使用delete进行销售。在此之前,你可以给你的朋友你的家庭住址,以便他们可以来找你。分配地址,导致复制它(例如IntNode *pNode = first;)。但是,你仍然只有一所房子。因此,无论您复制家庭住址多少次,您只能出售一次房屋。

我建议使用智能指针(例如std::unique_ptr),但我认为这个程序用于学习编程,所以不要这样做;)

答案 3 :(得分:0)

您需要在每个从列表中删除节点的函数上删除节点,而不是在插入时删除节点。不这样做会导致泄漏。

如果在破坏对象时仍有分配的节点,则需要迭代整个列表以删除所有节点。不这样做也会导致泄密。

我认为这是一项大学任务,因为有数百万经过实战考验的链表实施。

如果你在所有函数上保持最新的尾节点,你会做得更好,所以你可以避免迭代整个列表以在尾部插入一个节点。

答案 4 :(得分:0)

您显示的代码不足以判断您是否泄漏了内存。您显示负责分配的例程,但不显示您执行重新分配的代码。

如果你没有任何代码执行解除分配,那么是的,显然是泄漏。 C ++不执行自动垃圾收集,因为您可能习惯于其他语言。

您正在使用裸new,所以即使您确实有其他代码试图进行重新分配,也会有不正确的更改。

在C ++中,您通常不应该直接使用new运算符,而应该学会使用RAII来处理资源。 IntList可能使用拥有原始指针,这是另一个要避免的事情。在这种情况下,您可能应该使用unique_ptr<IntNode>。例如:

struct IntList {
  struct IntNode {
    unique_ptr<IntNode> next;
    int data;

    IntNode(int data) : data(data) {}
  };

  unique_ptr<IntNode> first;

  // returns a reference to the null pointer which terminates the linked list
  unique_ptr<IntNode> &get_tail() {
    if (!first) {
      return first;
    }
    IntNode *pNode = first.get(); // pNode is a non-owning pointer
    while (pNode->next) {
      pNode = pNode->next.get();
    }
    return pNode->next;
  }

  void push_back(int data) {
    get_tail() = make_unique<IntNode>(data);
  }
};

上述代码确实存在问题,但问题与内存泄漏无关。销毁列表后,first会自动销毁,会自动销毁first->next,依此类推。可以将如此多的元素插入到列表中,这种破坏链条会破坏&#39;函数堆栈,导致未定义的行为。

可以使用IntList析构函数修复问题,该析构函数以相反的顺序销毁节点:

IntList::~IntList() {
  while (first) {
    unique_ptr<IntNode> tmp = std::move(first);
    first = std::move(tmp->next);
  }
}

有趣的是,这是Rule of Three的例外示例。