从堆和内存泄漏中删除 C++ 数组

deleting c++ array from heap and memory leak

我有一个关于从堆内存中删除数组的问题。在一本书和 this blog and in other resources such as this one 上,我读到要从堆中删除数组,我们必须在 delete 关键字之后使用 [],这样如果我们不使用 []我们将有内存泄漏。

例如,考虑下面的代码。

//constructing array
int *s = new int[10];


// deleting array from heap
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无法检测到这种内存泄漏,是否有其他包可以检测到这种情况?

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

Martin Broadhurst 已经给出了正确的 。我将给出技术细节答案:

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

现在删除由两个不同的部分组成:

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

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

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

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