从堆中删除数组

时间:2017-11-04 13:32:23

标签: c++ arrays memory-leaks valgrind

我的问题是从堆内存中删除数组。我读了一本书和this blog以及其他资源like this one,并且所有人都说如果要从堆中删除数组,我们必须在[]函数之后使用delete,所以如果我们在不使用[]的情况下编写代码,然后我们泄露了内存。

例如,请考虑以下程序

int *s = new int[10];
delete [] s;

我在Linux中使用valgrind软件包测试了这个小程序(这个软件包可以检查错误编码产生的泄漏内存量)。通过Linux下面的命令,我们看到一切都没问题

sudo valgrind --leak-check=full ./<path_to_exe_file>

这是Linux命令的输出

 ==4565== HEAP SUMMARY:
 ==4565==     in use at exit: 0 bytes in 0 blocks
 ==4565==   total heap usage: 1 allocs, 1 frees, 40 bytes allocated
 ==4565== 
 ==4565== All heap blocks were freed -- no leaks are possible

但是当我尝试使用delete而不使用[]时出现了我的问题,当我检查valgrind的输出时,我看到所有堆内存都被释放,所以它是否正确?或valgrind不知道整个堆没有被释放,阵列的某些部分仍然在那里!! ??如果valgrind无法检测到这种泄露的内存,那么是否有任何可以检测到它的包。

2 个答案:

答案 0 :(得分:5)

在不使用delete的情况下在数组上调用[]会导致未定义的行为。未定义的行为可能是正确删除了数组,这似乎是您观察到的。但是,你不能依赖它。

答案 1 :(得分:2)

Martin Broadhurst已经给出了正确的language-lawyer answer。我将提供技术细节答案:

使用delete[]超过delete的要点是,delete运算符无法知道传递的指针是指向数组还是指向单个对象。因此,delete仅删除单个对象,而delete[]调用一些额外的魔法来恢复数组的大小,并继续删除所有元素。

现在删除包含两个不同的部分:

  1. 必须通过调用析构函数来销毁对象。对于数组,这意味着每个数组元素都有一个析构函数调用。

  2. 使用的内存必须标记为空闲,以便可以重复使用。这是C ++中全局operator delete()的工作。由于数组是连续存储的,因此这是对整个数组的单个调用。

  3. valgrind只关心记忆。因此,它挂钩内存分配函数,如malloc()free()operator new()operator delete()

    当您调用delete而不是delete[]时会发生什么,第一个对象被破坏,指针被传递到operator delete()operator delete()不知道存储在内存区域内的对象,它们无论如何都已被销毁,因此它会成功将内存区域标记为空闲。 valgrind看到此operator delete()电话,并且很高兴,因为所有内存都可以重复使用。但是,您的代码无法正确地破坏除第一个数组元素之外的所有数组元素。这很糟糕。