下面是c++源碼:c++
class X { private: int _x; public: X(int xx = 0) : _x(xx) {} ~X() {} }; int main() { X* xp = new X; delete xp; }
代碼很簡單,在main函數裏面先用new構造一個堆對象,而後用delelte釋放此對象。數組
接下來看構造堆對象的彙編碼:函數
: X* xp = new X; push 4;壓入對象的大小4byte,爲調用operator new函數傳遞參數 call ??2@YAPAXI@Z ; 調用operator new函數 add esp, 4;operator new調用結束,堆棧指針下移4byte,釋放爲operator new的參數分配的棧空間 mov DWORD PTR $T2579[ebp], eax;寄存器eax裏面存放申請到的堆空間首地址,存入臨時變量ST2579 cmp DWORD PTR $T2579[ebp], 0;將臨時變量ST2579的值與0比較,即檢測申請的對空間首地址是否爲NULL je SHORT $LN3@main;若是檢測結果相等,就跳轉到標號$LN3@main處執行,不然順序執行。這裏是順序執行 push 0;將0壓棧,爲調用構造函數傳遞參數 mov ecx, DWORD PTR $T2579[ebp];將臨時變量ST2579的值(裏面保存申請到的堆空間首地址)給寄存器ecx,做爲隱含參數傳遞給構造函數 ;這個隱含參數就是this指針 call ??0X@@QAE@H@Z ; 調用對象的構造函數 mov DWORD PTR tv70[ebp], eax;構造函數調用完畢,寄存器eax裏面存放的是對象首地址,這裏將首地址給臨時變量tv70 jmp SHORT $LN4@main;跳轉到標號$LN4@main處執行 $LN3@main: mov DWORD PTR tv70[ebp], 0;若是申請對空間失敗,將0給臨時變量tv70 $LN4@main: mov eax, DWORD PTR tv70[ebp];將tv70的值給寄存器eax mov DWORD PTR _xp$[ebp], eax;將寄存器eax的值給指針變量xp
從彙編碼能夠看到,用new構造堆對象時,大體的流程是:this
1 調用operator new申請堆空間編碼
2 對申請到的堆空間首地址進行檢查,防止申請失敗,返回空指針 spa
3 若是申請堆空間成功,就調用構造函數 並將堆空間首地址給xp指針。scala
所以,c++中用new申請堆空間與用malloc不一樣,前者自動檢測堆空間是否申請成功。代理
下面看析構堆對象的彙編碼:指針
: delete xp; mov ecx, DWORD PTR _xp$[ebp];將xp指針的值(即堆對象首地址)給寄存器ecx mov DWORD PTR $T2591[ebp], ecx;將ecx的值給臨時變量ST2591 mov edx, DWORD PTR $T2591[ebp];將臨時變量ST2591的值給寄存器edx mov DWORD PTR $T2590[ebp], edx;將寄存器edx裏面的值給臨時變量ST2590 cmp DWORD PTR $T2590[ebp], 0;將臨時變量ST2590的值與0比較,即檢測傳進來的堆對象首地址是否爲空指針 je SHORT $LN5@main;若是爲空指針,則跳轉到標號$LN5@main處執行,不然,順序執行。這裏順序執行 push 1;壓入對象類型標誌 1 單個對象 3 對象數組 0 只調用析構函數,不調用釋放堆空間(在多重繼承時有用)
mov ecx, DWORD PTR $T2590[ebp];將臨時變量ST2590的值給寄存器ecx,做爲隱函數參數(this指針)傳遞給析構代理函數 call ??_GX@@QAEPAXI@Z;調用析構代理函數 mov DWORD PTR tv75[ebp], eax;析構代理函數執行完畢,寄存器eax裏面保存堆對象首地址,將eax的值給臨時變量tv75 jmp SHORT $LN1@main;跳轉到標號$LN1@main處執行 $LN5@main: mov DWORD PTR tv75[ebp], 0;若是檢測堆對象首地址失敗,臨時變量tv75的值賦0 $LN1@main:;標號後面是main函數結束時的代碼
從彙編碼能夠看到,調用delete並不像operator new同樣直接調用析構函數和operator delete函數,而是調用了析構代理函數來完成operator delete的功能。之因此要用代理函數,是由於某些狀況下要釋放的對象不止一個。code
下面是析構代理函數彙編碼:
??_GX@@QAEPAXI@Z PROC ; X::`scalar deleting destructor', COMDAT ; _this$ = ecx push ebp mov ebp, esp push ecx;寄存器ecx裏面存儲的是對對象首地址,這裏壓棧的目的是爲了保存這個地址預留空間 mov DWORD PTR _this$[ebp], ecx;將ecx裏面的值存到剛纔預留的空間裏面 mov ecx, DWORD PTR _this$[ebp];將堆對象首地址給寄存器ecx,做爲隱含參數傳遞給析構函數 call ??1X@@QAE@XZ ; 調用析構函數 mov eax, DWORD PTR ___flags$[ebp];這裏獲取在調用析構代理函數以前,傳進來的標誌,並將其給寄存器eax and eax, 1;將eax裏面(對象類型標誌)的值與1相與 目的是判斷是否調用delete函數釋放堆空間
je SHORT $LN1@scalar;若是相與的結果爲0,則跳到標號$LN1@scalar處執行,不然,順序執行,這裏順序執行 mov ecx, DWORD PTR _this$[ebp];將堆對象首地址做爲給寄存器ecx push ecx;壓棧ecx的值,爲調用delete函數傳遞參數 call ??3@YAXPAX@Z ; 調用delete函數 add esp, 4;delete函數調用完畢,棧頂指針下移4byte,釋放爲delete函數的參數分配的棧空間 $LN1@scalar: mov eax, DWORD PTR _this$[ebp];將堆對象首地址給寄存器eax
;作爲返回值
mov esp, ebp pop ebp ret 4 ??_GX@@QAEPAXI@Z ENDP
從彙編碼能夠看到,析構代理函數先調用真正的析構函數,而後再調用delete函數釋放申請到的堆空間。在這中間有一個判斷過程,即經過對象類型標誌,判斷是否調用operator delete釋放堆空間。
經過上面的彙編碼,能夠看到delete的流程大體是:
1 檢測對象首地址值是否爲空
2 若是不爲空,就調用析構代理函數,不然,就不調用析構代理函數
3 在析構代理函數裏面調用對象的析構函數和delete函數(若是對象標誌不爲0的話)
從對c++中的delete調用過程來看,delete不會自動的將指針變量xp的值清零。所以,後續程序中若是使用xp指針仍然可行。指針變量xp和xp所指向的對象,最大的差異就是哪個聲明已經結束了。調用delete後,xp所指向的對象已將被析構,變得不合法,可是地址自己仍然表明一個合法的程序空間。
下面來看new和delete應用於對象數組的狀況
c++源碼以下:
class X { private: int _x; public: X(int xx = 0) : _x(xx) {} ~X() {} }; int main() { X* xp = new X[2]; delete [] xp; }
上述代碼在用new在堆中構造了2個對象,而後經過delete釋放。
下面裏看構造過程彙編碼:
X* xp = new X[2]; 00F035BD push 0Ch ;爲調用operator new運算符傳遞參數,即要申請的堆空間的大小 ;這裏每一個對象只有4byte,可是卻要申請12byte,是由於對於申請數組對象 ;堆空間首地址4byte用來存儲對象個數 00F035BF call operator new ;調用operator new運算符 00F035C4 add esp,4 ;operator new調用結束,棧頂指針下移4byte,釋放爲operator new傳遞參數而分配的棧空間 00F035C7 mov dword ptr [ebp-0F8h],eax;寄存器eax裏面保存了申請到的堆空間首地址 00F035CD mov dword ptr [ebp-4],0 ; 00F035D4 cmp dword ptr [ebp-0F8h],0 ;將返回的堆空間首地址與0比較,檢測是否申請成功 00F035DB je main+97h (0F03617h) ;若是申請不成功,即返回NULL,則跳到地址0F03617h處執行 不然,順序執行 這裏順序執行 00F035DD mov eax,dword ptr [ebp-0F8h] ;將堆空間首地址給寄存器eax 00F035E3 mov dword ptr [eax],2 ;將2寫入堆空間首地址所在內存,即在堆空間首地址4byte處保存對象個數 00F035E9 push offset X::~X (0F011DBh) ;將析構函數地址壓棧,做爲構造代理函數參數 00F035EE push offset X::`default constructor closure' ;將構造函數地址壓棧,做爲構造代理函數參數 00F035F3 push 2 ;將對象個數壓棧,做爲構造代理函數參數 00F035F5 push 4 ;將對象大小壓棧,做爲構造代理函數參數 00F035F7 mov ecx,dword ptr [ebp-0F8h] ;將堆空間首地址給寄存器ecx 00F035FD add ecx,4 ;ecx裏面的值加4 即跳過堆空間首地址4byte,此時ecx裏面保存的是第一個堆對象首地址 00F03600 push ecx ;壓棧ecx,做爲構造代理函數參數 00F03601 call `eh vector constructor iterator' (0F011E5h) ;調用構造代理函數 00F03606 mov edx,dword ptr [ebp-0F8h] ;將堆空間首地址給寄存器edx 00F0360C add edx,4 ;edx裏面的值加4 即跳過堆空間首地址4byte,此時edx裏面保存的是第一個堆對象首地址 00F0360F mov dword ptr [ebp-10Ch],edx 00F03615 jmp main+0A1h (0F03621h) ;跳到地址0F03621h處執行 00F03617 mov dword ptr [ebp-10Ch],0 ;若是堆空間申請失敗,賦空指針 00F03621 mov eax,dword ptr [ebp-10Ch] 00F03627 mov dword ptr [ebp-104h],eax 00F0362D mov dword ptr [ebp-4],0FFFFFFFFh 00F03634 mov ecx,dword ptr [ebp-104h] 00F0363A mov dword ptr [ebp-14h],ecx ;堆空間中第一個堆對象首地址給了xp
上面的彙編碼流程大體是:
1 調用operator new分配堆空間
2 調用構造代理函數構造堆對象,在調用構造代理函數時,經過壓棧,像其傳遞了5個參數,分別是 a)第一個堆對象首地址 b)堆對象大小
c)堆對象個數 d)構造函數地址 e)析構函數地址
3 傳回第一個堆對象首地址,而不是申請到的堆空間首地址
從上面彙編碼中還能夠看到,申請到的堆空間首地址用來存放的是對象的個數,所以,堆空間總大小並非對象大小 * 對象個數
下面是構造代理函數的彙編碼,只看相關部分:
00F03792 mov dword ptr [ebp-20h],0 00F03799 mov dword ptr [ebp-4],0 00F037A0 mov dword ptr [ebp-1Ch],0 ;將該內存的值初始化爲0 至關於for循環中,循環變量初始化爲0 00F037A7 jmp `eh vector constructor iterator'+52h (0F037B2h) ;跳轉到地址0F037B2h處執行 00F037A9 mov eax,dword ptr [ebp-1Ch] ;循環變量的值給寄存器eax 00F037AC add eax,1 ;寄存器eax裏面的值加1,即循環變量加1 00F037AF mov dword ptr [ebp-1Ch],eax ;將循環變量保存到內存中 00F037B2 mov ecx,dword ptr [ebp-1Ch] ;循環變量值給了寄存器ecx 00F037B5 cmp ecx,dword ptr [ebp+10h];將ecx裏面的值和 dword ptr [ebp+10h]內存所表明的值(對象個數2)比較,至關於循環變量的比較 00F037B8 jge `eh vector constructor iterator'+6Bh (0F037CBh) ;若是循環變量的值大於等於2,就跳轉到地址0F037CBh執行,不然順序執行 00F037BA mov ecx,dword ptr [ebp+8] ;將第一個堆對象對象首地址給寄存器ecx,做爲隱含參數給構造函數 00F037BD call dword ptr [ebp+14h] ;調用構造函數 00F037C0 mov edx,dword ptr [ebp+8] ;將第一個堆對象首地址給寄存器edx 00F037C3 add edx,dword ptr [ebp+0Ch] ;edx裏面的值加上對象大小,即修改指針,指向下一個堆對象首地址 00F037C6 mov dword ptr [ebp+8],edx ;堆對象首地址首地址保存到內存中 00F037C9 jmp `eh vector constructor iterator'+49h (0F037A9h);調轉到地址0F037A9h處執行 ;======================下面還有代碼,可是是完成構造函數以後,所以省略========================
構造代理函數的做用就是循環調用構造函數,依次構造數組中的每一對象
下面是釋放數組對象的彙編碼:
delete [] xp; 00A2363D mov eax,dword ptr [ebp-14h];將堆空間中第一個對象首地址給寄存器eax ;接下來是對eax的值的傳遞過程 00A23640 mov dword ptr [ebp-0E0h],eax 00A23646 mov ecx,dword ptr [ebp-0E0h] 00A2364C mov dword ptr [ebp-0ECh],ecx ;最後eax的值(即堆空間第一個對象首地址)給了ebp-0ECh所在內存 00A23652 cmp dword ptr [ebp-0ECh],0 ;檢測該內存裏面的值是否爲空 00A23659 je main+0F0h (0A23670h) ;若是爲空,跳到地址0A23670h處執行,不然,順序執行 這裏是順序執行 00A2365B push 3 ;壓入釋放對象類型標誌,1爲單個對象,3爲釋放對象數組,0僅表示執行析構函數,不釋放堆空間 ;壓入的值將做爲參數傳遞給析構代理函數 00A2365D mov ecx,dword ptr [ebp-0ECh] ;將堆空間中第一個對象首地址給寄存器ecx,做爲隱含參數傳遞給析構代理函數 00A23663 call X::`vector deleting destructor' (0A211EAh) ;調用vector deleting destructor函數
00A23668 mov dword ptr [ebp-10Ch],eax 00A2366E jmp main+0FAh (0A2367Ah) 00A23670 mov dword ptr [ebp-10Ch],0 13: 14: }
vector deleting destructor函數的彙編碼:
X::`vector deleting destructor': 00A21B10 push ebp 00A21B11 mov ebp,esp 00A21B13 sub esp,0CCh 00A21B19 push ebx 00A21B1A push esi 00A21B1B push edi 00A21B1C push ecx ;在調用該函數以前,ecx寄存器保存的是堆空間中,第一個對象的首地址 ;這裏將首地址壓入棧中保存,由於下面的代碼中將用到寄存器ecx 00A21B1D lea edi,[ebp-0CCh] 00A21B23 mov ecx,33h 00A21B28 mov eax,0CCCCCCCCh 00A21B2D rep stos dword ptr es:[edi] ;==========================================以上代碼爲函數入口部分==================== 00A21B2F pop ecx ;將棧頂裏面的值(保存着堆空間中第一個對象首地址)彈出,存到寄存器ecx, 00A21B30 mov dword ptr [ebp-8],ecx ;將對象首地址存放到ebp-8所表明的內存 00A21B33 mov eax,dword ptr [ebp+8] ;對象類型標標誌被保存在了寄存器eax中 00A21B36 and eax,2 ;將eax裏面的值和2相與,檢測是否爲對象數組標誌(由於標誌只能爲0 1 3,若是不爲3 結果確定爲0) 00A21B39 je X::`vector deleting destructor'+61h (0A21B71h);若是結果爲0,即不是對象數組標誌 ;跳轉到地址0A21B71h處執行 不然 順序執行 這裏順序執行 00A21B3B push offset X::~X (0A211DBh);將析構函數的地址壓棧,做爲參數傳遞給析構代理函數 00A21B40 mov eax,dword ptr [this] ;this指針指向堆空間中第一個對象首地址,這裏將該值給寄存器eax 00A21B43 mov ecx,dword ptr [eax-4] ;將向上偏移堆空間中第一個對象首地址4byte處內存內容(即申請到的堆空間首地址處 ;內存內容,該內存裏面保存着對象個數)給寄存器ecx 00A21B46 push ecx ;將ecx壓棧,做爲參數傳遞給析構代理函數 00A21B47 push 4 ;將對象大小壓棧,做爲參數傳遞給析構代理函數 00A21B49 mov edx,dword ptr [this] ;將堆空間中第一個對象首地址給寄存器edx 00A21B4C push edx ;將edx的值壓棧,做爲參數傳遞給析構代理函數 00A21B4D call `eh vector destructor iterator' (0A211F4h) ;調用析構代理函數 00A21B52 mov eax,dword ptr [ebp+8] ;獲取對象類型標誌,其值在調用該函數以前被壓入棧中 00A21B55 and eax,1;將寄存器eax的值和1相與,目的是判斷是否要調用delete函數釋放堆空間 00A21B58 je X::`vector deleting destructor'+59h (0A21B69h) ;若是相與結果爲0,就跳轉到地址0A21B69h處執行,不然 ;順序執行,這裏順序執行 00A21B5A mov eax,dword ptr [this] ;將堆空間中第一個對象首地址給寄存器eax 00A21B5D sub eax,4 ;將eax裏面的值減4,即修正了eax裏面的值,此時,eax裏面保存的是申請到的堆空間首地址 00A21B60 push eax ;將eax的值壓棧,做爲隱含參數傳遞給operator delete 00A21B61 call operator delete (0A21087h) ;調用operator delete,釋放堆空間 00A21B66 add esp,4 ;調用operator delete結束,釋放爲其傳參時的棧空間 00A21B69 mov eax,dword ptr [this];將堆空間中第一個對象首地址給寄存器eax 00A21B6C sub eax,4 ;將eax的值減4,即修正eax裏面的值,此時,eax裏面存儲的是申請到的堆空間首地址 00A21B6F jmp X::`vector deleting destructor'+80h (0A21B90h) ;跳轉到地址0A21B90h處執行 ;=====================下面代碼是傳進來的對象標誌不是3時執行的代碼===================== 00A21B71 mov ecx,dword ptr [this] ;若是對象標誌不是3,將跳轉到這裏執行。將堆空間中對象首地址給寄存器ecx,做爲隱含參數調用析構函數 00A21B74 call X::~X (0A211DBh) ;調用析構函數 00A21B79 mov eax,dword ptr [ebp+8] ;將對象類型標誌給寄存器eax 00A21B7C and eax,1 ;和上面同樣,判斷是否釋放堆空間 00A21B7F je X::`vector deleting destructor'+7Dh (0A21B8Dh) ;若是對象標誌爲0,就跳轉到地址0A21B8Dh處執行 ;不然,順序執行 00A21B81 mov eax,dword ptr [this] ;將堆對象首地址給寄存器eax 00A21B84 push eax ;壓入eax,做爲operator delete的參數 00A21B85 call operator delete (0A21087h) ;調用operator delete 00A21B8A add esp,4 ;operator delete調用結束,釋放爲其傳遞參數分配的棧空間 00A21B8D mov eax,dword ptr [this] ;將堆對象首地址給寄存器eax,做爲返回值 00A21B90 pop edi 00A21B91 pop esi 00A21B92 pop ebx 00A21B93 add esp,0CCh 00A21B99 cmp ebp,esp 00A21B9B call @ILT+305(__RTC_CheckEsp) (0A21136h) 00A21BA0 mov esp,ebp 00A21BA2 pop ebp 00A21BA3 ret 4
vector deleting destructor整體流程也是先調用析構代理函數,而後調用operator delete釋放空間(若是對象標誌不爲0的話),而且在調用析構代理函數時也傳進4個參數 a)堆空間中第一個對象首地址 b)對象大小 c)對象個數 d)虛函數地址
下面是析構代理函數的彙編碼:
mov ecx,dword ptr [ebp+0Ch] ;獲取堆對象個數,給寄存器ecx
00A236E0 imul ecx,dword ptr [ebp+10h] ;ebp+10h所表明的內存裏面存放對象大小,這條指令將ecx的值和ebp+10h
;的值相乘,將結果保存在ecx裏面
;ecx裏面此時保存的是全部堆對象所佔大小
00A236E4 add ecx,dword ptr [ebp+8] ;ebp+8所表明的的內存存放堆空間中第一個對象首地址,這裏將它與ecx相加
;結果保存在ecx裏面,此時ecx存放的是堆空間中最後一個對象後面的內存地址
;這麼作是爲了從最後一個對象開始析構
00A236E7 mov dword ptr [ebp+8],ecx ;將ecx的值保存到ebp+8所表明的內存
00A236EA mov dword ptr [ebp-4],0
00A236F1 mov edx,dword ptr [ebp+10h] ;將對象個數給寄存器edx,至關於for循環裏面的循環技術變量
00A236F4 sub edx,1 ;edx裏面的值減1
00A236F7 mov dword ptr [ebp+10h],edx ;將edx裏面的值存放到ebp+10h所表明的的內存
00A236FA js `eh vector destructor iterator'+6Dh (0A2370Dh) ;若是edx-1時爲父,跳轉到地址0A2370Dh處執行 00A236FC mov eax,dword ptr [ebp+8] ;將ebp+8內存的值(即最後一個堆對象後面的內存地址)給寄存器eax 00A236FF sub eax,dword ptr [ebp+0Ch] ;ebp+0ch所表明的內存存放對象大小,這裏用eax-對象大小 ;這裏依次獲得從最後一個堆對象到第一個堆對象首地址, ;存放到寄存器eax 00A23702 mov dword ptr [ebp+8],eax;將eax的值保存到ebp+8所表明的內存 00A23705 mov ecx,dword ptr [ebp+8];將堆對象首地址給ecx寄存器,做爲隱含參數傳遞給析構函數 00A23708 call dword ptr [ebp+14h] ;ebp+14h所表明的內存裏面存放的是析構函數地址,這裏調用析構函數 00A2370B jmp `eh vector destructor iterator'+51h (0A236F1h);跳轉到地址0A236F1h執行 ;後面是析構完對象以後的結束代碼
能夠看到,析構代理函數也是循環調用析構函數,以與構造對象相反的順序析構對象。
比較對單個堆對象調用delete和對堆對象數組調用delete[]能夠發現,兩種狀況最主要的差異是在用最後用delete釋放堆空間時,delete[]會對目標指針(即對delete來講,目標指針爲堆對象首地址,對delete[]來講,是堆中第一個堆對象首地址)進行減4調整.所以,若是是釋放單個對象堆空間,錯誤的使用delete[],那麼,執行中間檢測時,會判斷對象類型標記爲3,進行目標指針調整,結果會釋放錯誤的堆空間。同理,若是釋放對象數組,而錯誤的使用delet,那麼,執行中間檢測時,會判斷對象類型標記爲1,不進行目標指針調整,堆空間的釋放也會發生錯誤。
下面是c++源碼:
class X { private: int _x; public: X(int xx = 0) : _x(xx) {} virtual ~X() {} }; class Y { private: int _y; public: Y(int yy = 0) : _y(yy) {} virtual ~Y() {} }; class Z : public X, public Y { private: int _z; public: Z(int zz = 0) : _z(zz){} virtual ~Z() {} }; int main() { int* ip1 = new int[2]; delete [] ip1; int* ip2 = new int; delete ip2; }
c++代碼中ip1指向的是堆中基本類型int數組的首地址,ip1指向堆中單個基本類型int的首地址。
下面是mian函數裏面的彙編碼:
28: int* ip1 = new int[2]; 00141A3E push 8 ;將申請的堆空間大小壓棧,做爲參數傳遞給operator new 00141A40 call operator new (141177h) ;調用operator new 00141A45 add esp,4 ;棧頂指針減4 釋放爲調用operator new傳參時分配的棧空間 00141A48 mov dword ptr [ebp-104h],eax ;寄存器eax裏面存有申請到的堆空間首地址,下面 ;的代碼都是一些傳值操做 00141A4E mov eax,dword ptr [ebp-104h] 00141A54 mov dword ptr [ip1],eax ;eax的值傳給了指針變量ip1 29: delete [] ip1; 00141A57 mov eax,dword ptr [ip1] ;將ip1的值(指向堆空間首地址)給寄存器eax 00141A5A mov dword ptr [ebp-0F8h],eax ;下面是一些傳值操做 00141A60 mov ecx,dword ptr [ebp-0F8h] 00141A66 push ecx ;ecx裏面保存了堆空間首地址,這裏將ecx壓棧,爲調用delete傳參 00141A67 call operator delete (141082h) ;調用delete 00141A6C add esp,4 ;棧頂指針減4,釋放爲調用delete傳參時分配的棧空間 30: 31: int* ip2 = new int; 00141A6F push 4 ;將申請的堆空間大小壓棧,做爲餐宿傳遞給operator new 00141A71 call operator new (141177h);調用operator new 00141A76 add esp,4 ;棧頂指針減4 釋放爲調用operator new傳參時分配的棧空間 00141A79 mov dword ptr [ebp-0ECh],eax ;寄存器eax裏面存有申請到的堆空間首地址,下面 ;的代碼都是一些傳值操做 00141A7F mov eax,dword ptr [ebp-0ECh] 00141A85 mov dword ptr [ip2],eax ;eax的值給指針變量ip2 32: delete ip2; 00141A88 mov eax,dword ptr [ip2] ;將ip2的值(指向堆空間首地址)給寄存器eax 00141A8B mov dword ptr [ebp-0E0h],eax ;下面是一些傳值操做 00141A91 mov ecx,dword ptr [ebp-0E0h] 00141A97 push ecx ;ecx裏面保存了堆空間首地址,這裏將ecx壓棧,爲調用delete傳參 00141A98 call operator delete (141082h);調用delete 00141A9D add esp,4 ;棧頂指針減4,釋放爲調用delete傳參時分配的棧空間
從彙編碼能夠看到,因爲基本數據類型沒有構造函數和析構函數,所以,這兩種狀況都只是簡單的調用new分配空間,調用delete釋放空間。而且還能夠看到,和堆中對象數組不一樣,堆中基本類型數組沒有在申請到的堆空間首地址處存放對象個數,ip1,ip2都直接指向的是各自申請到的堆空間首地址,正由於如此,對於基本類型,delete和delete[]效果同樣。