先看一段代码:
int main(void)
{
int *pI = new int;
int *pArray = new int[10];
int size = *(pArray-1);
delete pI;
delete [] pArray; // delete是如何知道pArray数组大小的?
return 0;
}
看反编译后代码,没能直接找到答案,于是在网上搜索发现这样一篇文章:《Mismatching scalar and vector new and delete》。文章中说明了内存布局大概是这样:
这个结论肯定是正确的,但是我却没能在内存中找到这个记录数组大小的地址。再看反编译代码,例子中分别new了一个对象和一个数组,例子最后使用delete[]分别删除了这两个对象。从C++角度来说,第一个delete是scalar "delete",第二个delete [] 是vector "delete"。这两种delete调用应该不一样才对,但从反编译代码看,两处调用完全相同。
; int __cdecl main() _main proc near var_5C= dword ptr -5Ch var_58= dword ptr -58h p= dword ptr -54h var_50= dword ptr -50h size= dword ptr -0Ch push ebp mov ebp, esp sub esp, 5Ch push ebx push esi push edi push 4 ; size call j_??2@YAPAXI@Z ; operator new(uint) mov [ebp+var_5C], eax mov eax, [ebp+var_5C] mov [ebp+pI], eax nop push 28h ; size call j_??2@YAPAXI@Z ; operator new(uint) mov [ebp+var_58], eax mov eax, [ebp+var_58] mov [ebp+pArray], eax nop mov eax, [ebp+pArray] mov ecx, [eax-4] mov [ebp+size], ecx nop mov eax, [ebp+pI] mov [ebp+p], eax mov ecx, [ebp+p] push ecx ; p call j_??3@YAXPAX@Z ; operator delete(void *) nop mov eax, [ebp+pArray] mov [ebp+var_50], eax mov ecx, [ebp+var_50] push ecx ; p call j_??3@YAXPAX@Z ; operator delete(void *) xor eax, eax pop edi pop esi pop ebx mov esp, ebp pop ebp retn _main endp |
结论:
- 通过观察"new"调用了HeapAlloc函数,而这一函数使用可以将内存分配情况用结构体保存起来,"delete"估计就是通过这一结构体得到数组大小的。也就是说C++这一语法特点是借用了HeapAlloc等函数对Windows堆内存的管理方式实现的。
未知&待研究:
- scalar "new" 与 vector "delete []"出现不匹配的使用时究竟会不会出现问题
-
通过反编译验证结论。尤其是"delete []"