先写一个demo,里面有new[],delete[],使用C++11 MTd选项编译:
#include <string>
int main()
{
auto pS = new std::string[10];
delete[] pS;
return 0;
}
new的大小为0x11c,十进制284,相当与10*28 + 4。4个额外申请的长度就是保存数组大小用的。
auto pS = new std::string[10];
009C970D push 11Ch
009C9712 call operator new[] (09C376Ch)
009C9717 add esp,4
009C971A mov dword ptr [ebp-0F8h],eax
在new返回的地址先写入的数组的长度10,注意返回给用户的地址是这个地址+4后的长度。
009C972E je main+9Ah (09C976Ah)
009C9730 mov eax,dword ptr [ebp-0F8h]
009C9736 mov dword ptr [eax],0Ah
数组对象开始调用构造函数初始化:
009C973C push 9C3FB9h
009C9741 push 9C31DBh
009C9746 push 0Ah //对象的个数
009C9748 push 1Ch //对象的大小
009C974A mov ecx,dword ptr [ebp-0F8h]
009C9750 add ecx,4
009C9753 push ecx //将new返回的地址+4就是第一个对象的首地址
009C9754 call `eh vector constructor iterator' (09C3EECh)
009C9759 mov edx,dword ptr [ebp-0F8h]
009C975F add edx,4
009C9762 mov dword ptr [ebp-10Ch],edx
//注意这里返回的地址是+4的,这是用户拿到的地址。复制流是这样的[ebp-10ch]->[ebp-104h]->ecx->pS
009C9768 jmp main+0A4h (09C9774h)
009C976A mov dword ptr [ebp-10Ch],0
009C9774 mov eax,dword ptr [ebp-10Ch]
009C977A mov dword ptr [ebp-104h],eax
009C9780 mov dword ptr [ebp-4],0FFFFFFFFh
009C9787 mov ecx,dword ptr [ebp-104h]
009C978D mov dword ptr [pS],ecx
所以我们调用new[]多个对象的时候,返回地址-4上保存着这个对象数组的大小。
接着我们看delete[]的时候是怎么用的:上来就是空指针检查,即使我们C++代码里面没有写。
delete[] pS;
009C9790 mov eax,dword ptr [pS]
009C9793 mov dword ptr [ebp-0E0h],eax
009C9799 mov ecx,dword ptr [ebp-0E0h]
009C979F mov dword ptr [ebp-0ECh],ecx
009C97A5 cmp dword ptr [ebp-0ECh],0 //检查pS是否为NULL
009C97AC je main+0F3h (09C97C3h)
009C97AE push 3
delete[] pS;
009C97B0 mov ecx,dword ptr [ebp-0ECh]
009C97B6 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::`vector deleting destructor' (09C4216h)
跟入vector deleting destructor函数看看:先[pS-4]取数组的的长度,调用析构函数,然后delete释放内存。
009C78DB push 9C3FB9h
009C78E0 mov eax,dword ptr [this] //取pS的值
009C78E3 mov ecx,dword ptr [eax-4] //取对象数组的长度
009C78E6 push ecx //string对象的个数10
009C78E7 push 1Ch //strig对象的大小
009C78E9 mov edx,dword ptr [this]
009C78EC push edx
009C78ED call `eh vector destructor iterator//调用string析构函数
009C78F2 mov eax,dword ptr [ebp+8]
009C78F5 and eax,1
009C78F8 je std::basic_string<char,std::char_traits<char>,std::allocator<char> >::`vector deleting destructor'+59h (09C7909h)
009C78FA mov eax,dword ptr [this]
009C78FD sub eax,4 //pS-4才是申请堆block的首地址,然后delete释放。
009C7900 push eax
009C7901 call operator delete[] (09C3136h)
009C7906 add esp,4
总结:delete[]参数不用输入数组的长度,是CRT实现new的时候在堆userdata首地址放上了数组长度,new返回的地址是申请到地址+4的值。然后delete[]释放的时候,用传入地址-4拿数组长度,实现数组释放。