【问题标题】:C++ array of pointer memory leaks指针内存泄漏的 C++ 数组
【发布时间】:2011-11-03 19:34:35
【问题描述】:

在我的班级中,我有一个动态分配的指针数组。我的声明:

 array = new Elem* [size];
 for (int i = 0; i < size; i++) {
    array[i] = NULL;
 }

所以有一个指针数组,其中每个指针指向一个简单的 Elem 结构体。

主要问题是,我应该如何正确地释放数组。如果我只使用:

for (int i = 0; i < size; i++) {
   delete array[i];
}

Valgrind 报告了 1 个未释放的块,该块被追溯到 'array = new Elem* [size];' 的行状态。

另一方面,如果我添加到前面的代码:

delete array;

我认为是正确的,valgrind 报告了 0 个未释放的块,这是完美的,但它报告了

Mismatched free() / delete / delete []

正好在“删除数组;”所在的行是。我也试过'delete []array',但那也只是“1个未释放的块”!如果有人能以正确的方式向我解释,将不胜感激。

编辑: 所以使用:

for (int i = 0; i < size; i++) {
   delete array[i];
}
delete[] array;

可能工作正常。它在我的一个班级(我有两个类似的班级)中工作,另一个仍然报告一些小泄漏。我认为这只是某个地方的一个小错误,但 valgrind 仍然指向

array = new Elem* [size];

站着。

EDIT2: 我也解决了这个问题,感谢您的辛苦贡献!

【问题讨论】:

  • 它在哪里说未释放的块得到了分配?
  • 让您的生活更轻松:删除以上所有内容,并使用 Boost ptr_vector
  • 我知道这并不能回答您的问题,但是您是否有某些原因不能使用 std::vector 来大大简化内存管理?
  • 确实有,这是一项学校作业,我们不允许使用它,可能关键是要学习如何正确地做到这一点。
  • @aGr:在这种情况下,“家庭作业”标签是否合适?它也可能阻止其他人推动矢量角度。 :)

标签: c++ memory-leaks valgrind


【解决方案1】:

你需要:

delete [] array;

因为它是一个数组。

我刚刚注意到您的说明,您也尝试过 - 这是正确的做法,所以我不知道为什么您仍然会收到错误。

编辑:这值得更彻底的解释。

当您使用new 创建指针时,指针可能指向单个元素或元素数组,具体取决于您使用的语法。但是两种情况下的指针类型都是一样的!编译器依靠您知道指针指向的内容并相应地处理它。

Elem ** single = new Elem*;    // pointer to one pointer
single[0] = new Elem;          // OK
single[1] = new Elem;          // runtime error, but not compile time

Elem ** array = new Elem* [2]; // pointer to array of pointers
array[0] = new Elem;           // OK
array[1] = new Elem;           // OK

当你删除一个指针时,会为它指向的对象或数组的每个元素调用析构函数。但是由于指针类型在每种情况下都是相同的,编译器依赖于你给它正确的语法,所以它知道该怎么做。

delete single;
delete [] array;

在您的情况下,数组的元素也是指针,并且指针没有析构函数。这意味着这些指针不会被删除,如果你不先删除它们,它们就会成为内存泄漏。在最终删除之前有一个循环单独删除它们是正确的。

【讨论】:

  • OP 确实需要delete [],但我不会称它为数组。
  • @cnicutar,如果它不是一个数组,那么你会怎么称呼它? new [] 语法分配一个数组。
  • @cnicutar,是的,一个指向数组的指针。我希望我们现在达成一致。
  • 它是一个数组(嗯,一个指向数组的指针)。虽然它不同于“数组类型”
  • @cnicutar,我必须根据您的评论纠正自己 - 指针类型实际上是指向单个元素的指针,但它指向的内存仍然是一个数组。不知何故,内存子系统会跟踪差异。
【解决方案2】:

您应该释放数组中的所有内容(如果是动态分配的),然后释放数组本身。

for (int i = 0; i < size; i++) { // only free inside if dynamically allocated - not if just storing pointers
   delete array[i];
}
delete[] array; // necesarry

【讨论】:

  • 你的意思是他应该删除数组中指针指向的所有对象,然后使用delete[]删除数组中的对象(即指针)和数组本身。
  • @DavidSchwartz,说数组中的对象被删除是不准确的,而是它们被销毁了。指针没有析构函数,因此在该步骤中不会发生任何事情。
  • @MarkRansom 指针有析构函数。 C++ 有它们,因此模板可以使用内置类型。
  • delete[] 的语义是删除数组中的对象。在这种情况下,这并没有多大作用——但关键是说delete[] 没有“释放数组中的所有内容”是错误的。 OP 的问题是他有一个指针数组。
  • @DavidSchwartz:马克是正确的。每个元素都被销毁(由于析构函数很简单,这对于原始指针来说是无操作的),然后立即释放整个块。每个元素都不是单独释放的。
【解决方案3】:

删除数组的语法如下:

delete[] array;

您的for 循环删除数组元素指向的对象很好。数组本身的删除是唯一的问题。您需要both for 循环和 delete[] 来处理数组本身。

for (int i = 0; i < size; i++) {
   delete array[i];
}
delete[] array;

我怀疑您尝试过使用for 循环或delete[],但不能同时使用。如果这样做时仍然存在泄漏或错误,那么您需要向我们展示分配作为数组元素的指针的代码。


使用std::vector&lt;&gt; 代替数组意味着您可以不再担心这些琐碎的细节并转向更高级别的抽象。

【讨论】:

  • @David 好的,我编辑了它。令人惊讶的是,信号在所有噪音中变得如此之多。
【解决方案4】:

在这种情况下,您需要两者

for (int i = 0; i < size; i++) {
   delete array[i];
}
delete[] array;

每次调用 new 时,您只调用一次 delete

请注意,虽然您需要在此处调用delete[] array(因为您使用new[] 分配了它),但delete[] 运算符确实调用由元素指向的对象的析构函数数组。这是因为delete[] 运算符在数组中的objects 上调用析构函数,并且您的数组包含指针但不包含对象。指针本身没有析构函数。

【讨论】:

  • 我认为,形式上,指针类型有微不足道的析构函数,它们什么都不做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-31
  • 2015-12-15
  • 2013-09-30
  • 2014-08-25
  • 1970-01-01
  • 1970-01-01
  • 2016-05-14
相关资源
最近更新 更多