摘自:http://topic.csdn.net/u/20080826/16/0c479e3d-737f-45c7-995e-bd316f5fa166.html
赫然发现,其实这已经是个老问题了,以前csdn上已经有过讨论了。http://topic.csdn.net/u/20070712/07/57c7cfc6-7314-400d-86d2-230a72581ea5.html。或许也有不少启发。
现将各位c/c++友所述意见,结合相关资料,总结如下,希望有所帮助:
1.delete 与delete【】都会释放所有内存,它们的不同点仅在于,根据得到的类型信息是单个指针还是指向数组的指针,来决定调用析构函数的次数。而编译器对所要删除的那个指针到底是指向的单一对象还是对象数组的判断依据就是'【】'的有无。若有'[]'编译器得到的类型信息就是指向数组的指针,然后调用多次析构函数;若没有‘【】’编译器得到的类型信息就是单个指针,只调用一次析构函数。
其实delete操作本身就是做两件事:
(1)针对此处内存调用析构函数
(2)然后释放该处内存。
(详见《Effective C++》(2nd)item 5 或 (3rd)item 16)。
2.vc6.0和vs05中,delete和delete[]语句都是调用operator delete(),在vs05中调试,如86楼‘sungoco2’兄所贴代码所显示,跟进operator delete()中,可看到有这样一句“_free_dbg( pUserData, pHead->nBlockUse );”而free要正确工作,有一个必要前提,即传给它的地址确实是当初申请的内存首地址,否则,会出现lihao2008123 所说的assert错误。这也就是我在24,25楼所提到的问题的表象解释。即在重载delete操作符后,某种情况下发现delete操作的指针地址不同于new操作所获取的地址。从而出现assert错误,程序崩溃。
3.那么什么情况下,二者操作的指针地址不匹配呢?
大家还记得那个前面讨论过的4字节吗?问题就在这里,且不说这4字节是干什么的,单说它的来源。经过反复实验测试,发现只要对象类型定义有显式析构函数,那么这个4字节就肯定存在。也就是说,哪怕是我们自定义的一个类类型对象,只要我们没有为这个类定义析构函数,那么这个4字节问题就不会出现;那么该用delete【】的时候,用delete也不会报错;那么该用delete的时候,用delete【】也不会报错,那么...
本论题,由于内置类型没有析构函数,而string有析构函数,这样一种巧合,而把问题局限在了内置类型与自定义类型这样的分类范围上。所以我们这个问题准确的说,应该是显式析构函数的存在影响了delete与delete【】的处理。
4.好,现在,我们可以思考这个4字节的来源了。其实,91楼的‘guyue6670 ’兄已经提到过,“差的这4个字节为一个隐藏的vtable指针”。相信拜读过Lippman的《Inside The C++ Object Model》的c/c++友们都对他在第1章中对c++对象模型的描述印象深刻。其中就将类定义的析构函数划归到虚表中,而对象本身保存的是指向该虚表的指针(一般情况下,指针本身是4字节的)。这样问题就解决了。(详见Stanley B.Lippman著的《Inside The C++ Object Model》)
附注:
为慎重起见,听取taodm大师之言,本人不敢保证以上解释能应用于所有厂家编译器的处理方式。仅在vc6.0,vs05,dev c++中测试。可能与编译器相关。
//****************************************************************************
输出如下:
new[]: 00142A90; size: 10
return: 00142A90
delete[]: 00142A90
new[]: 00142A90; size: 44
return: 00142A94
delete[]: 00142A90
new[]: 00142A90; size: 40
return: 00142A90
delete[]: 00142A90
//***********************************************************
class Two
{
int a;
public:
Two( int b=0)
{
a = b;
}
~Two( void )
{
a= 0;
}
};
int main(int argc, char* argv[])
{
char *p = new char;
char *p1= new char[10];
Two *p2 = new Two( 10 );
Two *p3 = new Two[20];
p1[0] = *p;
delete p;
delete p1;
delete p2;
delete p3;
delete []p3;
return 0;
}
汇编代码:
0041EF30 push ebp
0041EF31 mov ebp,esp
0041EF33 push 0FFh
0041EF35 push offset __ehhandler$_main (00426f36)
0041EF3A mov eax,fs:[00000000]
0041EF40 push eax
0041EF41 mov dword ptr fs:[0],esp
0041EF48 sub esp,9Ch
0041EF4E push ebx
0041EF4F push esi
0041EF50 push edi
0041EF51 lea edi,[ebp-0A8h]
0041EF57 mov ecx,27h
0041EF5C mov eax,0CCCCCCCCh
0041EF61 rep stos dword ptr [edi]
16: char *p = new char;
0041EF63 push 1
0041EF65 call operator new (0040ec40)
0041EF6A add esp,4
0041EF6D mov dword ptr [ebp-20h],eax
0041EF70 mov eax,dword ptr [ebp-20h]
0041EF73 mov dword ptr [ebp-10h],eax
17: char *p1= new char[10];
0041EF76 push 0Ah
0041EF78 call operator new (0040ec40) 调用new
0041EF7D add esp,4
0041EF80 mov dword ptr [ebp-24h],eax
0041EF83 mov ecx,dword ptr [ebp-24h]
0041EF86 mov dword ptr [ebp-14h],ecx
18: Two *p2 = new Two( 10 );
0041EF89 push 4
0041EF8B call operator new (0040ec40) 调用new
0041EF90 add esp,4
0041EF93 mov dword ptr [ebp-2Ch],eax
0041EF96 mov dword ptr [ebp-4],0
0041EF9D cmp dword ptr [ebp-2Ch],0
0041EFA1 je main+82h (0041efb2)
0041EFA3 push 0Ah
0041EFA5 mov ecx,dword ptr [ebp-2Ch]
0041EFA8 call @ILT+510(Two::Two) (00401203) 调用构造器
0041EFAD mov dword ptr [ebp-58h],eax
0041EFB0 jmp main+89h (0041efb9)
0041EFB2 mov dword ptr [ebp-58h],0
0041EFB9 mov edx,dword ptr [ebp-58h]
0041EFBC mov dword ptr [ebp-28h],edx
0041EFBF mov dword ptr [ebp-4],0FFFFFFFFh
0041EFC6 mov eax,dword ptr [ebp-28h]
0041EFC9 mov dword ptr [ebp-18h],eax
19: Two *p3 = new Two[20];
0041EFCC push 54h
0041EFCE call operator new (0040ec40)
0041EFD3 add esp,4
0041EFD6 mov dword ptr [ebp-34h],eax
0041EFD9 mov dword ptr [ebp-4],1
0041EFE0 cmp dword ptr [ebp-34h],0
0041EFE4 je main+0E4h (0041f014)
0041EFE6 push offset @ILT+525(Two::~Two) (00401212) 保存了析构地址
0041EFEB push offset @ILT+505(Two::`default constructor closure') (004011fe)
0041EFF0 mov ecx,dword ptr [ebp-34h]
0041EFF3 mov dword ptr [ecx],14h
0041EFF9 push 14h
0041EFFB push 4
0041EFFD mov edx,dword ptr [ebp-34h]
0041F000 add edx,4
0041F003 push edx
0041F004 call `eh vector constructor iterator' (0041f1a0) 调用矢量构造迭代器
0041F009 mov eax,dword ptr [ebp-34h]
0041F00C add eax,4
0041F00F mov dword ptr [ebp-5Ch],eax
0041F012 jmp main+0EBh (0041f01b)
0041F014 mov dword ptr [ebp-5Ch],0
0041F01B mov ecx,dword ptr [ebp-5Ch]
0041F01E mov dword ptr [ebp-30h],ecx
0041F021 mov dword ptr [ebp-4],0FFFFFFFFh
0041F028 mov edx,dword ptr [ebp-30h]
0041F02B mov dword ptr [ebp-1Ch],edx
20:
21: p1[0] = *p;
0041F02E mov eax,dword ptr [ebp-14h]
0041F031 mov ecx,dword ptr [ebp-10h]
0041F034 mov dl,byte ptr [ecx]
0041F036 mov byte ptr [eax],dl
22:
23: delete p;
0041F038 mov eax,dword ptr [ebp-10h]
0041F03B mov dword ptr [ebp-38h],eax
0041F03E mov ecx,dword ptr [ebp-38h]
0041F041 push ecx
0041F042 call operator delete (00409f20) 调用delete
0041F047 add esp,4
24: delete p1;
0041F04A mov edx,dword ptr [ebp-14h]
0041F04D mov dword ptr [ebp-3Ch],edx
0041F050 mov eax,dword ptr [ebp-3Ch]
0041F053 push eax
0041F054 call operator delete (00409f20) 调用delete
0041F059 add esp,4
25: delete p2;
0041F05C mov ecx,dword ptr [ebp-18h]
0041F05F mov dword ptr [ebp-44h],ecx
0041F062 mov edx,dword ptr [ebp-44h]
0041F065 mov dword ptr [ebp-40h],edx
0041F068 cmp dword ptr [ebp-40h],0
0041F06C je main+14Dh (0041f07d)
0041F06E push 1
0041F070 mov ecx,dword ptr [ebp-40h]
0041F073 call @ILT+530(Two::`scalar deleting destructor') (00401217) 调用标量析构器
0041F078 mov dword ptr [ebp-60h],eax
0041F07B jmp main+154h (0041f084)
0041F07D mov dword ptr [ebp-60h],0
26: delete p3;
0041F084 mov eax,dword ptr [ebp-1Ch]
0041F087 mov dword ptr [ebp-4Ch],eax
0041F08A mov ecx,dword ptr [ebp-4Ch]
0041F08D mov dword ptr [ebp-48h],ecx
0041F090 cmp dword ptr [ebp-48h],0
0041F094 je main+175h (0041f0a5)
0041F096 push 1
0041F098 mov ecx,dword ptr [ebp-48h]
0041F09B call @ILT+530(Two::`scalar deleting destructor') (00401217) 调用标量析构器
0041F0A0 mov dword ptr [ebp-64h],eax
0041F0A3 jmp main+17Ch (0041f0ac)
0041F0A5 mov dword ptr [ebp-64h],0
27: delete []p3;
0041F0AC mov edx,dword ptr [ebp-1Ch]
0041F0AF mov dword ptr [ebp-54h],edx
0041F0B2 mov eax,dword ptr [ebp-54h]
0041F0B5 mov dword ptr [ebp-50h],eax
0041F0B8 cmp dword ptr [ebp-50h],0
0041F0BC je main+19Dh (0041f0cd)
0041F0BE push 3
0041F0C0 mov ecx,dword ptr [ebp-50h]
0041F0C3 call @ILT+535(Two::`vector deleting destructor') (0040121c) 调用矢量析构器
0041F0C8 mov dword ptr [ebp-68h],eax
0041F0CB jmp main+1A4h (0041f0d4)
0041F0CD mov dword ptr [ebp-68h],0
28: return 0;
0041F0D4 xor eax,eax
29: }
0041F0D6 mov ecx,dword ptr [ebp-0Ch]
0041F0D9 mov dword ptr fs:[0],ecx
0041F0E0 pop edi
0041F0E1 pop esi
0041F0E2 pop ebx
0041F0E3 add esp,0A8h
0041F0E9 cmp ebp,esp
0041F0EB call __chkesp (0040bfc0)
0041F0F0 mov esp,ebp
0041F0F2 pop ebp
0041F0F3 ret