3.2 new一个类对象数组的过程
上面详细解析了为一个对象申请内存的过程,再来看一下为一个类申请对象数组时具体发现一些什么情况。还是上面CMemoryItem类,代码如下:
CMemoryItem* pItem = new CMemoryItem[10];
delete[] pItem;
我们在CMemoryItem* pItem = new CMemoryItem[10];设一个断点看看具体的汇编代码如下:
00401D49 add eax,0Ah
00401D4C push eax
00401D4D push offset THIS_FILE (00416690)
00401D52 push 54h
00401D54 call operator new (0040233e)
先分析一下这段代码,前3句是一样的,第4句将要申请的内存空间长度入栈;但是申请了10个元素,每个元素8个字节,是要80个字节换算成十六进制就是50字节,但这里入栈时却多了4个字节,这4个字节是做什么用的呢?再来看一段汇编代码:
00401D59 add esp,0Ch
00401D5C mov dword ptr [ebp-1Ch],eax
00401D5F mov dword ptr [ebp-4],0
00401D66 cmp dword ptr [ebp-1Ch],0
00401D6A je CTestMemAllocateDlg::OnDelete+8Ah (00401d9a)
00401D6C push offset @ILT+55(CMemeryItem::~CMemeryItem) (0040103c)
00401D71 push offset @ILT+15(CMemeryItem::CMemeryItem) (00401014)
00401D76 mov ecx,dword ptr [ebp-1Ch]
00401D79 mov dword ptr [ecx],0Ah
00401D7F push 0Ah
00401D81 push 8
00401D83 mov edx,dword ptr [ebp-1Ch]
00401D86 add edx,4
00401D89 push edx
00401D8A call `eh vector constructor iterator' (004023c0)
00401D8F mov eax,dword ptr [ebp-1Ch]
00401D92 add eax,4
00401D95 mov dword ptr [ebp-28h],eax
00401D98 jmp CTestMemAllocateDlg::OnDelete+91h (00401da1)
这代码段调用new函数之后的代码,先看00401D5C处的代码eax是new函数返回的内存地址,它被存入了dword ptr [ebp-1Ch],记下这个地址后面构造时会用到这个地址。00401D5F—00401D6A这段代码是编译器自动插入检查NEW函数申请内存是否成功的。00401D6C将类的析构函数地址入栈,00401D71将类的构造函数地址入栈;00401D76这句要注意一下dword ptr [ebp-1Ch](为类数组申请的内存首地址)MOV给了ECX,下面边这句把OAH(十进制10)放到入到了内存的前四个字节;00401D7F—00401D89是分别将数组元素的个数、元素的长度、数组的起始地址(申请内存块的第五个字节开始),00401D8A调用一个函数来构造这个数组,为了更深入的理解对象数组内存的申请,进入这个函数看看其中的详细过程,看下面的汇编代码:
004023C0 push ebp
004023C1 mov ebp,esp
004023C3 push 0FFh
004023C5 push offset _LIBID_ATLLib+10h (004154b0)
004023CA push offset _except_handler3 (004027c0)
004023CF mov eax,fs:[00000000]
004023D5 push eax
004023D6 mov dword ptr fs:[0],esp
004023DD add esp,0F0h
004023E0 push ebx
004023E1 push esi
004023E2 push edi
|