Transferred from: http://www.cppblog.com/weiym/archive/2013/11/17/204292.html
The behavior behind new in C + + has previously been written to understand the behavior behind new in C + +, but it is only a generalities, no conclusive evidence, what do the C + + compilers do behind the scenes from a compilation point of view? Our code is simple, as follows: #include <iostream> class A{public:virtual void print (){std::cout <<;}virtual ~a (){std::cout << "~a ()";}}; Class B:public A{public:virtual void print (){std::cout <<;}}; int _tmain (int argc, _tchar* argv[]) {A * p = new B ();p->print ();delete p;return 0;} I use WinDbg to see the assembly code generated by the main function as follows: newtest!wmain:00aa1020 push esi00aa1021 6a04 push 4 00aa1023 e8b403 0000 call newtest!operator New (00AA13DC)//Call operator new allocate a space of 4 bytes 00aa1028 83c404 &nb Sp add esp,400aa102b 85c0 test &NBSP ; eax,eax00aa102d 740a je newtest!wmain+0x19 (00aa1039) 00aa10 2f c7005421aa00 mov DWORD ptr [Eax],offset newtest! B:: ' vftable ' (00aa2154)//write the virtual table address to the first 4 bytes of the object address (virtual table pointer) 00aa1035 8bf0 mov esi,eax00aa1037 eb02 jmp newtest!wmain+0x1b (00aa103b) 00aa1039 33f 6 xor ESI,ESI00AA103b 8b06 mov Eax,dword ptr [esi]00aa103d 8b10 & nbsp mov Edx,dword ptr [eax]00aa103f 8bce mov ecx,esi00aa1041 ffd2 call &NBSP;EDX//calling the first function within a virtual table print00aa1043 8b06   ; mov Eax,dword ptr [esi]00aa1045 8b5004 &NBSP;M OV Edx,dword ptr [eax+4]00aa1048 6a01 push &NBSP;100AA104A 8 BCE mov ecx,esi00aa104c ffd2 &NB Spcall EdX//calls the second function within a virtual table (destructor)00aa104e 33c0 xor eax,eax00aa1050 5e Pop esi00aa1051 c3 ret00aa1052 cc int 3 from the above code we can see that we construct a total of 4 bytes of the B object, and these four bytes contain the object's virtual table pointer, for C + + object memory layout, for C + + object memory layout, you can see my this articleExplore the C + + object model. At the same time, we can see that C + + is really a virtual table to achieve polymorphism. The above code also tells us why we cannot implement polymorphism in constructors by calling virtual functions. Because the virtual table is generated in the constructor of the final derived class, the virtual table is not generated when the base class constructor is executed. 0:000> u 00aa13dcnewtest!operator new:00aa13dc ff25cc20aa00 jmp DWORD ptr [Newtest!_imp_?? 2YAPAXIZ (00aa20cc)] inside is a direct jump:0:000> u poi (00aa20cc) l10msvcr90!operator new:74603e99 8bff mov edi,edi74603e9b/ push   ; ebp74603e9c 8bec mov ebp,esp74603e9e 83ec0c &NB Sp sub ESP,0CH74603EA1 eb0d &NBSP;JMP Msvcr90!ope Rator new+0x17 (74603eb0) 74603ea3 ff7508 push dword ptr [ebp+8]74603ea6 E85 9DCFBFF call &NBSP;MSVCR90!_CALLNEWH (745c1b04) 74603eab i & nbsp pop ECX74603EAC 85c0 test eax,eax74603eae 740f & nbsp &NBsp je msvcr90!operator new+0x26 (74603EBF) 74603eb0 ff7508 Push dword ptr [ebp+8]
74603eb3 e887feffff Call Msvcr90!malloc (74603d3f)74603eb8-pop ecx74603eb9 85c0 test Eax,eax74603ebb 74e6 JE msvcr90!opera Tor new+0xa (74603EA3) 74603ebd C9 Leavewe can see that operator new is finally called malloc, and if you go further down, you will find that malloc is calling kernel32! HeapAlloc, and HeapAlloc called ntdll!.Rtlallocateheap, on the heap layout and allocation algorithm, you can seesoftware Debugging for Zhang Banque the behavior behind the new operator is demonstrated above:First call operator new allocate space, we can overload operator new, define our own memory allocation algorithmThe constructor is then called on the allocated space to create the object, and the virtual table pointer may be assigned inside the constructor. Next we look at the behavior behind the delete. we see that the delete call is the second function in the virtual table, and we first look at the contents of the virtual tables:0:000> DPS 00aa215400aa2154 00aa1010 newtest! B::p rint [f:\test\newtest\newtest\newtest.cpp @ 26]00aa2158 00aa1060 newtest! B:: ' scalar deleting destructor ' 00aa215c 0000000000aa2160 0000004800aa2164 00000000 There are 2 functions in the virtual table above, one is print, and the other is destructor, we look at the contents of the second function:0:000> u 00aa1060 l10newtest! B:: ' scalar deleting destructor ': 00aa1060 push esi00aa1061 8BF1 mov esi,ecx00aa1063 c7064821aa00 mov &NBSP ; DWORD ptr [Esi],offset newtest! A:: ' vftable ' (00aa2148) 00aa1069 a15820aa00 mov Eax,dword ptr [Newtest!_imp_?coutstd (00 aa2058)]00aa106e push eax00aa106f e84c010000 call NewTest!std::operator<<<std::char_traits<char> > (00aa11c0) 00aa1074 83c404 add esp,400aa1077 f644240801 test byte ptr [esp+8],100aa107c 7409 &N Bsp je newtest! B:: ' scalar deleting destructor ' +0x27 (00aa1087) 00aa107e push &NB sp;esi00aa107f e806030000 call newtest!operator Delete (00aa138a) 00aa1084 83c404 add esp,400aa1087 8bc6 mov eax,esi00aa1089 5e pop esi00aa108a c20400 &NB Sp ret 4we can see that the imaginary table is B.Scalar deleting destructor, it contains two parts of code, one is the code of the destructor that we really define, and part of it is operator delete (operator delete will call free, and the free call kernel32! HeapFree). Here'sScalar deleting destructor is obviously not a destructor for B ~b (), which is a function that the compiler helped me to use for delete type B objects.let's look at the pointer to the array type, how the C + + compiler handles it, and change the code to the following:int _tmain (int argc, _tchar* argv[]) {A * p = new A[10];delete []p;return 0;The following is the generated assembly code: newtest!wmain:01181030 6a2c push 2Ch 01181032 e8c4030000 call Newtest!operator new[] (0 11813FB)//via operator new Assignment 44 own 01181037 83c404 add esp,40118103a 85c0 test eax,eax0118103c 7444 Je newtest!wmain+0x52 (01181082) 0118103e-in-a-push ESI0118103f 6810101801 Push offset newtest! Destructors for A::~a (01181010)//a01181044 6800111801 Push offset newtest! A::a (01181100)//a constructor01181049 6a0a push 0Ah//100118104b 8d7004 Lea Esi,[eax+4]//crossed the first four bytes0118104e 6A04 Push 4//object size01181050 The//esi of the object list (spanning the first four bytes) .01181051 c7000a000000 mov dword ptr [eax],0ah//Head four bytes write to List of objects (x)01181057 e812040000 call newtest! ' eh Vector constructor iterator ' (0118146e)0118105c 85f6 Test esi,esi0118105e 7421 JE newtest!wmain+0x51 (01181081)01181060 837efc00 cmp dword ptr [esi-4],0//Determine whether the number of objects is 001181064 8D46FC Lea Eax,[esi-4]//address with number of objects saved to eax01181067 740f JE newtest!wmain+0x48 (01181078)01181069 8b06 mov eax,dword ptr [esi]//Take A's virtual table address0118106b 8b5004 mov edx,dword ptr [eax+4]//second function in virtual table0118106e 6a03 Push 301181070 8BCE mov ecx,esi01181072 ffd2 call edx01181074 5e pop esi01181075 33c0 xor eax,eax01181077 c3 ret Focus look aboveRedcode, we can see that in the new array, the compiler helps us do the following things:(1) Call an array of operator new[] to allocate memory, size 4 + sizeof (object) * Count, where the first four bytes are the number of objects (2) called newtest! ' eh Vector constructor iterator (pArr Ayaddress, sizeof (object), object_count, pfunconstructor, pfundestructor), which pfundestructor is a destructor, pfunconstructor is a constructor, object_count is the number of objects, sizeof (object) is the object size, Parrayaddress is the starting address. , below we disassemble newtest! ' eh vector constructor iterator: 0:000> u 0118146e l50newtest! ' eh vector Constructor iterator ': 0118146e 6a10 push 10h01181470 6890221801 &nbs P push offset newtest!__rtc_tzz+0x8 (01182290) 01181475 e8d2040000 call &NBSP;NEWTEST!__SEH_PROLOG4 (0118194c) 0118147a 33c0 xor EAX, eax0118147c 8945e0 mov DWORD ptr [ebp-20h],eax0118147f 8945fc &NBSP ; mov DWORD ptr [ebp-4],eax01181482 8945e4 mov DWORD ptr [ebp-1ch],eax01181485 8b45e4 &nb Sp mov Eax,dword ptr [ebp-1ch]//Temporary count, initial 001181488 3b4510 &NBSP ; cmp Eax,dword ptr [ebp+10h] //Compare temporary count and number of objects 0118148b 7d13 &NBSP ; jge newtest! ' eh Vector constructor iterator ' +0x32 (011814a0)//exit loop 0118148d 8b7508 &NB If the temporary count is greater than the number of objects Sp mov Esi,dword ptr [ebp+8]//Save first parameter (start address) to esi01181490 8BCE mov Ecx,esi//Assign this pointer to ECX01181492 ff5514call DWORD ptr [ebp+14h]//calling constructor01181495 03750c add Esi,dword ptr [ebp+0ch]//Move pointer, plus object size 01181498 897508 mov DWORD ptr [Ebp+8],esi//Save new object address to the first parameter 0118149b ff45e4 &NB Sp inc DWORD ptr [ebp-1ch]//Increase temporary count 0118149e ebe5 &NBSP;JMP &nbs P newtest! ' eh Vector constructor iterator ' +0x17 (01181485) 011814a0 c745e001000000 mov DWORD ptr [ Ebp-20h],1011814a7 c745fcfeffffff mov DWORD ptr [ebp-4],0fffffffeh011814ae e808000000 & Nbsp;call newtest! ' eh Vector constructor iterator ' +0x4d (011814BB) 011814b3 e8d9040000 Call &NBSP;NEWTEST!__SEH_EPILOG4 (01181991) 011814b8 c21400 ret 14h& nbsp; we can see that the newtest! ' eh vector, constructor iterator, is the function that the compiler helps us generate, which is to call the constructor for every object in the array. Then we'll look at the array form of delete [] what the hell is going on behind it? Focus on the top!PurpleThe code:Newtest!wmain: ....01181060 837efc00 cmp dword ptr [esi-4],0//Determine whether the number of objects is 001181064 8D46FC Lea Eax,[esi-4]//address with number of objects saved to eax01181067 740f JE newtest!wmain+0x48 (01181078)01181069 8b06 mov eax,dword ptr [esi]//Take A's virtual table address0118106b 8b5004 mov edx,dword ptr [eax+4]//second function in virtual table0118106e 6a03 Push 301181070 8BCE mov ecx,esi01181072 ffd2 call edx....you can see that it saves the object list start address to ECX, and then calls the second function in the object's virtual table, and the incoming parameter is 3, we first look at the object's virtual tables content:0:000> DPS 01182148 01182148 01181000 newtest! A::p rint [f:\test\newtest\newtest\newtest.cpp @ 11]0118214c 01181090 newtest! A:: ' vector deleting destructor ' Let's see what the function really did:0:000> u 01181090 l40newtest! A:: ' vector deleting destructor ': 01181090 push ebx01181091 8a5c2408 mov Bl,byte ptr [esp+8]01181095 + &N Bsp push esi01181096 8bf1 mov esi,ecx01181098 f6c302 test bl,2//need to call destructors 0118109b 742b &NB Sp;je newtest! A:: ' vector deleting destructor ' +0x38 (011810C8) 0118109d 8b46fc mov EAX,DWO Rd PTR [esi-4]011810a0 push &NBSP;EDI011810A1 6810101801 &nbsP push offset newtest! A::~a (01181010) 011810a6 8D7EFC lea EDI,[ESI-4]011810A9 & nbsp push &NBSP;EAX011810AA 6a04 push &NBSP;4 011810AC push esi011810AD e87f040000Call newtest! ' eh vector destructor iterator '(01181531)011810B2 f6c301 Test bl,1//need to free memory 011810b5 7409 JE newtest! A:: ' vector deleting destructor ' +0x30 (011810C0) 011810b7 $ push EDI011810b8 e85f030000Call newtest!operator delete[] (0118141c)011810BD 83c404 add esp,4011810c0 8BC7 mov eax,edi011810c2 5f pop edi011810c3 5e pop esi011810c4 5b pop ebx011810c5 c20400 ret 4 You can see that it's internally called newtest! ' eh Vector destructor iterator, and if again trace newtest! ' eh vector destructor iterator,will look at all the objects in the array call the destructor, and finally call operator delete[] to free all memory. the key to what we can see in arrays new[] and delete[] is that the C + + compiler holds the number of objects n 4 bytes before the start address of the array, followed by the construction and destruction of N times based on this number of values. Finally, the above analysis is limited to VS2008, in fact, in line with the C + + standard, each C + + compiler has its own different implementations. We can see that the C + + compiler has done a lot of things behind the scenes, may be inline with our functions, can also modify and produce some other functions, and this is a lot of C developers can't stand the thing, so at the kernel level, many people prefer to use C to reduce the interference behind the compiler. Finally think about it, what if our code writes like this? int _tmain (int argc, _tchar* argv[]) {A * p = new B[ten]; delete []p;return 0;}
Behind new and delete in C + +