删除是否等于删除?

IP_ADAPTER_INFO *ptr=new IP_ADAPTER_INFO[100]; 

如果我自由使用

 delete ptr; 

会导致内存泄漏,如果不是,那么为什么?

这是由VS2005生成的反汇编代码

 ; delete ptr; 0041351D mov eax,dword ptr [ptr] 00413520 mov dword ptr [ebp-0ECh],eax 00413526 mov ecx,dword ptr [ebp-0ECh] 0041352C push ecx 0041352D call operator delete (4111DBh) 00413532 add esp,4 ; delete []ptr; 00413535 mov eax,dword ptr [ptr] 00413538 mov dword ptr [ebp-0E0h],eax 0041353E mov ecx,dword ptr [ebp-0E0h] 00413544 push ecx 00413545 call operator delete[] (4111E5h) 0041354A add esp,4 

这是否会导致内存泄漏,擦拭硬盘,让你怀孕,让讨厌的恶魔追赶你的公寓,或让一切工作正常,没有明显的问题,是不明确的。 这可能是用一个编译器,用另一个编译器改变,用一个新的编译器版本,每个新的编译,月亮阶段,你的心情,或根据通过最后一个晴天处理器的中微子数量下午。 或者它可能不会。

所有这一切以及无数其他可能性都被归纳为一个术语: 未定义的行为

只要远离它。

只是在某些操作系统和编译器上的一些“未定义”行为的例子。 希望可以帮助人们debugging他们的代码。

testing1

 #include <iostream> using namespace std; int main() { int *p = new int[5]; cout << "pass" << endl; delete p; return 0; } 

testing2

 #include <iostream> using namespace std; int main() { int *p = new int; cout << "pass" << endl; delete[] p; return 0; } 

testing3

 #include <iostream> using namespace std; struct C { C() { cout << "construct" << endl; } ~C() { cout << "destroy" << endl; } }; int main() { C *p = new C[5]; cout << "pass" << endl; delete p; return 0; } 

testing4

 #include <iostream> using namespace std; struct C { C() { cout << "construct" << endl; } ~C() { cout << "destroy" << endl; } }; int main() { C *p = new C; cout << "pass" << endl; delete[] p; return 0; } 
  • Windows 7 x86,msvc 2010.使用默认选项进行编译,即启用exception处理程序。

testing1

 pass 

testing2

 pass 

testing3

 construct construct construct construct construct pass destroy # Then, pop up crash msg 

testing4

 construct pass destroy destroy destroy destroy destroy destroy destroy ... # It never stop until CTRL+C 
  • Mac OS X 10.8.5,llvm-gcc 4.2或gcc-4.8生成相同的输出

testing1

 pass 

testing2

 pass 

testing3

 construct construct construct construct construct pass destroy a.out(71111) malloc: *** error for object 0x7f99c94000e8: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug zsh: abort ./a.out 

testing4

 construct pass a.out(71035) malloc: *** error for object 0x7f83c14000d8: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug zsh: abort ./a.out 
  • Ubuntu 12.04,AMD64,gcc 4.7

testing1

 pass 

testing2

 pass 

testing3

 construct construct construct construct construct *** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x0000000001f10018 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7fe81d878b96] ./a.out[0x400a5b] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7fe81d81b76d] ./a.out[0x4008d9] ======= Memory map: ======== .... zsh: abort (core dumped) ./a.out 

testing4

 construct destroy destroy destroy destroy destroy destroy destroy destroy ... destroy destroy *** glibc detected *** ./a.out: free(): invalid pointer: 0x00000000016f6008 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7fa9001fab96] ./a.out[0x400a18] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7fa90019d76d] ./a.out[0x4008d9] ======= Memory map: ======== ... zsh: abort (core dumped) ./a.out 

它通常不会泄漏,因为如果POD析构函数是微不足道的,并且不需要调用它们,那么delete只是释放数组占用的内存。 内存释放只需要一个指针值,所以它将被返回到堆中。 数组拥有连续的内存块,所以释放可以成功,就好像它是一个单独元素的释放一样。

但不要依赖这个,因为它是未定义的行为。 也许它运作良好,也许发生了一些可怕的事情,在这个编译器上工作,对另一个工作不起作用,许多人感谢你的错误。

看到这个答案的细节。

如果A指向通过新的T [n]分配的数组,则必须通过delete [] A删除它。

为什么?

删除和删除[]之间的区别很简单 – 前者销毁一个标量对象,后者销毁一个数组。

更多信息在这里和这里 。

更新1(错误):

如果在使用新的T [n]分配时使用delete(而不是delete []),则只有第一个元素被释放,而其他元素不会被析构,这将导致内存泄漏 。 为什么? 这就是Bjarne Stroustrup和其他人devise语言的方式。 而且它不是编译器变化的。 如果一个编译器以不同的方式解除分配,那只是不遵循标准 。 C ++编程语言 ,章节6.2.6.2和19.4.5。

更新2(正确):

我承认我的错误关于使用新的T [n]分配使用删除操作符的行为。 阅读提到的文件,我没有find确切的描述,所以我想在这种情况下,行为将是不确定的 ,并将从编译器到编译器。 例如,AFAIK,MSVC编译器将产生与GCC不同的代码。 请忽略更新1

delete仅为指向的元素 (如果需要)调用适当的析构函数 ,然后释放内存块

delete [] :为其数组中的每个元素调用适当的析构函数 (如果需要的话),然后释放内存块

对于POD数组,它不会泄漏 (大多数编译器)。 例如, MSVCPOD数组生成相同删除删除[]代码。

就个人而言,我认为C / C ++可以没有运营商删除[]。 编译器知道对象的大小和分配的内存大小在运行时是已知的,因此知道是否是一个指针数组并且以正确的方式configuration内存是非常简单的。

编辑:

好的,伙计们。 你可以testing你的编译器,并说是否泄漏?

尝试作为一个编译器开发人员思考。 我们有新的新的[]删除删除[] 。 每个新的都有自己的删除 。 似乎完美和完整。 让我们看看当你调用delete []时发生了什么?

 1. call vector destructor for an object 2. actual free memory 

什么是POD的析构函数? 没有! 所以,调用删除数组的POD不会泄漏! 即使它打破了标准。 即使不推荐。

EDIT2:

这是由VS2008生成的反汇编代码:

 operator delete[]: 78583BC3 mov edi,edi 78583BC5 push ebp 78583BC6 mov ebp,esp 78583BC8 pop ebp 78583BC9 jmp operator delete (78583BA3h)