new/delete操作符的彙編級粗略過程
MSVC6.0 DEBUG ASM
預設情況下(沒有重載new運算符) new int 結果上完全等價于 (int *)malloc(sizeof(int))。new int[n]完全等價于(int *)malloc(sizeof(int) * n)
這個可以推廣到所有非類類型。
對于類,假設ClassA,new ClassA; 相當于(ClassA *)malloc(sizeof(ClassA))之後用傳回的指針調用ClassA的預設構造函數,再傳回那個指針
new ClassA(參數表) 基本上和上面一樣,隻是會調用參數表對應的構造方法
new ClassA[n]比較複雜,一般會進行類似 int *t = (int *)malloc(sizeof(ClassA) * n + sizeof(int)); *t = n; ClassA *r = (ClassA *)(t + 1); for (int i = 0; i < n; i++, (r++)->ClassA::ClassA()); return (ClassA *)(t + 1);的操作。簡單說就是申請記憶體,儲存個數,然後對每個對象調用構造函數
對于非類類型 delete p和delete[] p相同,等價于free(p)
對于類,假設還是ClassA,delete p等價于 p->ClassA::~ClassA(); free(p); 先調用析構函數,然後釋放記憶體
對于delete[] p,并且p用new []申請。對應上面的new []實作,delete[] p會進行 int *t = (int *)p - 1; for (int i = 0; i < *t; i++, (p++)->ClassA::~ClassA()); free(t);的操作。
注:以上這段摘自百度知道http://zhidao.baidu.com/question/200118329.html中的其他答案。。。
(一)内置類型。 Ⅰ.new 内置類型:(如int *a=new int;或int *b=new int[5]) 1.将operator new函數的參數nSize壓棧,通常等于待配置設定空間長度(Eg: 1或5)。 2.調用void* __cdecl operator new(size_t nSize),寄存器傳遞配置設定成功後的指針,主調函數用臨時變量接收。(注1:函數調用方式__cdecl表明參數壓棧順序為由右及左,調用完畢後由主調函數清除入棧參數恢複棧頂。注2:operator new函數執行過程中有機制用于記錄配置設定的長度。該函數具體過程也不簡單,參見其他網頁) 3.将傳回值傳給目标指針。
Ⅱ.delete 内置類型:(如delete a;或delete[] a;;delete b;或delete[] b;,效果均相同)(注:若類類型無析構函數,則其delete操作符與内置類型完全相同!) 1.将待處理指針p壓棧。 2.調用 void __cdecl operator delete(void* p) 。(注:調用方式也是__cdecl。因operator new函數執行過程中有用于記錄配置設定的長度的外部資料結構,故在delete過程中可擷取該指針對應配置設定的空間長度,進而正确釋放。調用方式加不加中括号都是同樣效果!)
(二)類類型。 分兩種類别讨論:有無自定義構造函數和有無析構函數。以下條目是有構造函數和析構函數時的過程。 若去掉析構函數,與有析構函數相比:new單個對象的過程相同;但new對象數組則不同,雖過程相近,但配置設定區直接是類對象數組,而沒有記錄元素個數的單元。 若去掉析構函數,則new等于operator new直接按所需空間配置設定,然後初始化;而delete與内置類型完全相同,無需析構,delete操作符可混用! 若去掉構造函數但有析構函數,則調用operator new後無需初始化,但new對象數組時配置設定空間時仍多用一個記憶體單元記錄個數。 若構造析構均無,則退化為内置類型。
(注:對于在函數中定義的局部變量,其過程相對以下條目,隻是少了operator new/delete函數的調用)
Ⅲ. new 類類型的單個對象:(如int *c=new CString;) 1.将operator new函數的參數nSize壓棧,即該類的sizeof值(Eg: 4)。 2.調用void* __cdecl operator new(size_t nSize),寄存器傳遞配置設定成功後的指針,主調函數用臨時變量接收。 3.将構造函參進棧,将配置設定所得對象的指針傳入ECX(類成員函數的調用方式預設為thiscall方式),調用适當的類構造函數。(若無構造函數,則無此步驟。) 3.将對象指針傳給目标指針。
Ⅳ. new 類類型的數組:(如int *d=new CString[5];) 1.将operator new函數的參數nSize壓棧,即該數組的sizeof值+4(Eg: 5*4+4=0x18h)。 2.調用void* __cdecl operator new(size_t nSize),寄存器傳遞配置設定成功後的指針,主調函數用臨時變量接收。将已配置設定區的首個單元填上元素個數。(注:配置設定區的首個記憶體單元将存儲數組元素個數,其後的記憶體單元才是類對象數組的實際空間,故nSize要大4位元組)。 3.将eh vector constructor iterator函數的參數壓棧,從左往右分别是首個對象的this指針,sizeof類類型,數組元素個數,類預設構造函數,類析構函數。 調用eh vector constructor iterator全局函數,即矢量構造函數,将每個對象均初始化。(注:析構函數可能是用于對象初始化過程失敗後的復原,即将已構造的對象再析構使之無效。)(若無析構函數,則調用vector constructor iterator全局函數,它有4個參數,不含類析構函數。若無構造函數,則無此步驟。) 4.将首個對象的指針,即已配置設定區指針的下一單元,傳給目标指針。
Ⅴ . delete 類類型的單個變量:(如delete c;) 1.将立即數1壓棧,将待處理指針p(new操作符傳回的對象指針)傳給ECX。(注:1代表delete操作符類别delete ;,不含方括号) 2.調用類的 scalar deleting destructor函數 。其具體過程為:
(1)将對象指針傳入ECX,調用類析構函數。 (2)測試之前入棧的立即數,若為奇數則進行(3),否則跳過并結束。 (3)将對象指針壓棧,調用void __cdecl operator delete(void* p)。
Ⅵ.delete 類類型的數組:(如delete[] d;)
1.将立即數3壓棧,将待處理指針p(new[]操作符傳回的首對象指針)傳給ECX。(注:3代表delete操作符 類别 delete[]; ) 2.調用類的 vector deleting destructor 。其具體過程為:
(1)将對象指針傳入ECX,調用類析構函數。 (2)測試之前入棧的立即數,若為2或3則從(3)順序執行;若不滿足則不進行逐個析構,隻對首個對象調用類析構函數,并跳到(4)。 (3)将eh vector destructor iterator全局函數的參數壓棧,從左往右分别是首個對象的this指針,sizeof類類型,數組元素個數(從首對象位址的上一記憶體單元中讀出),類析構函數。然後調用該函數。 (4)測試之前入棧的立即數,若為奇數則将首對象位址的上一單元位址入棧(因這是實際由operator new所配置設定空間的首位址),調用void __cdecl operator delete(void* p);若不滿足則跳過operator delete的調用。最後EAX均傳遞operator new函數所配置設定的空間首位址。
測試代碼:
class Two
{
int a;
public:
Two( int b =0) { a = 5; };
~Two( void ) { a= 0; };
};
int main(int argc, char* argv[])
{
char *p0 = new char;
char *p1= new char[10];
delete p0;
delete p1;
Two a;
Two b[3];
Two *p2 = new Two;
Two *p3 = new Two(10);
Two *p4 = new Two[7];
p1[0] = *p0;
delete p2;
delete p3;//delete[] p3;
delete[] p4;//delete p4;
return 0;
}
生成彙編:
PUBLIC [email protected]@[email protected]@Z ; Two::Two
PUBLIC [email protected]@[email protected] ; Two::~Two
PUBLIC [email protected]@QAEXXZ ; Two::`default constructor closure'
PUBLIC [email protected]@[email protected] ; Two::`scalar deleting destructor'
PUBLIC [email protected]@[email protected] ; Two::`vector deleting destructor'
PUBLIC _main
EXTRN [email protected]@[email protected]:NEAR ; `eh vector constructor iterator'
EXTRN [email protected]@[email protected]:NEAR ; `eh vector destructor iterator'
EXTRN [email protected]@Z:NEAR ; operator new
EXTRN [email protected]@Z:NEAR ; operator delete
EXTRN __except_list:DWORD
EXTRN __chkesp:NEAR
EXTRN ___CxxFrameHandler:NEAR
_main PROC NEAR ; COMDAT
; 40 : {
push ebp
mov ebp, esp
push -1
push __ehhandler$_main
mov eax, DWORD PTR fs:__except_list
push eax
mov DWORD PTR fs:__except_list, esp
sub esp, 192 ; 000000c0H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-204]
mov ecx, 48 ; 00000030H
mov eax, -858993460 ; ccccccccH
rep stosd
; 41 : char *p0 = new char;
push 1
call [email protected]@Z ; operator new
add esp, 4
mov DWORD PTR $T297[ebp], eax
mov eax, DWORD PTR $T297[ebp]
mov DWORD PTR _p0$[ebp], eax
; 42 : char *p1= new char[10];
push 10 ; 0000000aH
call [email protected]@Z ; operator new
add esp, 4
mov DWORD PTR $T298[ebp], eax
mov ecx, DWORD PTR $T298[ebp]
mov DWORD PTR _p1$[ebp], ecx
; 43 : delete p0;
mov edx, DWORD PTR _p0$[ebp]
mov DWORD PTR $T299[ebp], edx
mov eax, DWORD PTR $T299[ebp]
push eax
call [email protected]@Z ; operator delete
add esp, 4
; 44 : delete p1;
mov ecx, DWORD PTR _p1$[ebp]
mov DWORD PTR $T300[ebp], ecx
mov edx, DWORD PTR $T300[ebp]
push edx
call [email protected]@Z ; operator delete
add esp, 4
; 45 : Two a;
push 0
lea ecx, DWORD PTR _a$[ebp]
call [email protected]@[email protected]@Z ; Two::Two
mov DWORD PTR __$EHRec$[ebp+8], 0
; 46 : Two b[3];
push OFFSET FLAT:[email protected]@[email protected] ; Two::~Two
push OFFSET FLAT:[email protected]@QAEXXZ ; Two::`default constructor closure'
push 3
push 4
lea eax, DWORD PTR _b$[ebp]
push eax
call [email protected]@[email protected] ; `eh vector constructor iterator'
mov BYTE PTR __$EHRec$[ebp+8], 1
; 47 : Two *p2 = new Two;
push 4
call [email protected]@Z ; operator new
add esp, 4
mov DWORD PTR $T302[ebp], eax
mov BYTE PTR __$EHRec$[ebp+8], 2
cmp DWORD PTR $T302[ebp], 0
je SHORT $L303
push 0
mov ecx, DWORD PTR $T302[ebp]
call [email protected]@[email protected]@Z ; Two::Two
mov DWORD PTR -120+[ebp], eax
jmp SHORT $L304
$L303:
mov DWORD PTR -120+[ebp], 0
$L304:
mov ecx, DWORD PTR -120+[ebp]
mov DWORD PTR $T301[ebp], ecx
mov BYTE PTR __$EHRec$[ebp+8], 1
mov edx, DWORD PTR $T301[ebp]
mov DWORD PTR _p2$[ebp], edx
; 48 : Two *p3 = new Two(10);
push 4
call [email protected]@Z ; operator new
add esp, 4
mov DWORD PTR $T306[ebp], eax
mov BYTE PTR __$EHRec$[ebp+8], 3
cmp DWORD PTR $T306[ebp], 0
je SHORT $L307
push 10 ; 0000000aH
mov ecx, DWORD PTR $T306[ebp]
call [email protected]@[email protected]@Z ; Two::Two
mov DWORD PTR -124+[ebp], eax
jmp SHORT $L308
$L307:
mov DWORD PTR -124+[ebp], 0
$L308:
mov eax, DWORD PTR -124+[ebp]
mov DWORD PTR $T305[ebp], eax
mov BYTE PTR __$EHRec$[ebp+8], 1
mov ecx, DWORD PTR $T305[ebp]
mov DWORD PTR _p3$[ebp], ecx
; 49 : Two *p4 = new Two[7];
push 32 ; 00000020H
call [email protected]@Z ; operator new
add esp, 4
mov DWORD PTR $T310[ebp], eax
mov BYTE PTR __$EHRec$[ebp+8], 4
cmp DWORD PTR $T310[ebp], 0
je SHORT $L311
push OFFSET FLAT:[email protected]@[email protected] ; Two::~Two
push OFFSET FLAT:[email protected]@QAEXXZ ; Two::`default constructor closure'
mov edx, DWORD PTR $T310[ebp]
mov DWORD PTR [edx], 7
push 7
push 4
mov eax, DWORD PTR $T310[ebp]
add eax, 4
push eax
call [email protected]@[email protected] ; `eh vector constructor iterator'
mov ecx, DWORD PTR $T310[ebp]
add ecx, 4
mov DWORD PTR -128+[ebp], ecx
jmp SHORT $L312
$L311:
mov DWORD PTR -128+[ebp], 0
$L312:
mov edx, DWORD PTR -128+[ebp]
mov DWORD PTR $T309[ebp], edx
mov BYTE PTR __$EHRec$[ebp+8], 1
mov eax, DWORD PTR $T309[ebp]
mov DWORD PTR _p4$[ebp], eax
; 50 :
; 51 : p1[0] = *p0;
mov ecx, DWORD PTR _p1$[ebp]
mov edx, DWORD PTR _p0$[ebp]
mov al, BYTE PTR [edx]
mov BYTE PTR [ecx], al
; 52 :
; 53 : delete p2;
mov ecx, DWORD PTR _p2$[ebp]
mov DWORD PTR $T314[ebp], ecx
mov edx, DWORD PTR $T314[ebp]
mov DWORD PTR $T313[ebp], edx
cmp DWORD PTR $T313[ebp], 0
je SHORT $L315
push 1
mov ecx, DWORD PTR $T313[ebp]
call [email protected]@[email protected] ; Two::`scalar deleting destructor'
mov DWORD PTR -132+[ebp], eax
jmp SHORT $L316
$L315:
mov DWORD PTR -132+[ebp], 0
$L316:
; 54 : delete p3;//delete[] p3;
mov eax, DWORD PTR _p3$[ebp]
mov DWORD PTR $T318[ebp], eax
mov ecx, DWORD PTR $T318[ebp]
mov DWORD PTR $T317[ebp], ecx
cmp DWORD PTR $T317[ebp], 0
je SHORT $L319
push 1
mov ecx, DWORD PTR $T317[ebp]
call [email protected]@[email protected] ; Two::`scalar deleting destructor'
mov DWORD PTR -136+[ebp], eax
jmp SHORT $L320
$L319:
mov DWORD PTR -136+[ebp], 0
$L320:
; 55 : delete[] p4;//delete p4;
mov edx, DWORD PTR _p4$[ebp]
mov DWORD PTR $T322[ebp], edx
mov eax, DWORD PTR $T322[ebp]
mov DWORD PTR $T321[ebp], eax
cmp DWORD PTR $T321[ebp], 0
je SHORT $L323
push 3
mov ecx, DWORD PTR $T321[ebp]
call [email protected]@[email protected] ; Two::`vector deleting destructor'
mov DWORD PTR -140+[ebp], eax
jmp SHORT $L324
$L323:
mov DWORD PTR -140+[ebp], 0
$L324:
; 56 : return 0;
mov DWORD PTR $T325[ebp], 0
mov BYTE PTR __$EHRec$[ebp+8], 0
push OFFSET FLAT:[email protected]@[email protected] ; Two::~Two
push 3
push 4
lea ecx, DWORD PTR _b$[ebp]
push ecx
call [email protected]@[email protected] ; `eh vector destructor iterator'
mov DWORD PTR __$EHRec$[ebp+8], -1
lea ecx, DWORD PTR _a$[ebp]
call [email protected]@[email protected] ; Two::~Two
mov eax, DWORD PTR $T325[ebp]
; 57 : }
mov ecx, DWORD PTR __$EHRec$[ebp]
mov DWORD PTR fs:__except_list, ecx
pop edi
pop esi
pop ebx
add esp, 204 ; 000000ccH
cmp ebp, esp
call __chkesp
mov esp, ebp
pop ebp
ret 0
_TEXT ENDS
; COMDAT [email protected]@[email protected]@Z
_TEXT SEGMENT
_this$ = -4
[email protected]@[email protected]@Z PROC NEAR ; Two::Two, COMDAT
; 35 : Two( int b =0) { a = 5; };
push ebp
mov ebp, esp
sub esp, 68 ; 00000044H
push ebx
push esi
push edi
push ecx
lea edi, DWORD PTR [ebp-68]
mov ecx, 17 ; 00000011H
mov eax, -858993460 ; ccccccccH
rep stosd
pop ecx
mov DWORD PTR _this$[ebp], ecx
mov eax, DWORD PTR _this$[ebp]
mov DWORD PTR [eax], 5
mov eax, DWORD PTR _this$[ebp]
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 4
[email protected]@[email protected]@Z ENDP ; Two::Two
_TEXT ENDS
; COMDAT [email protected]@[email protected]
_TEXT SEGMENT
_this$ = -4
[email protected]@[email protected] PROC NEAR ; Two::~Two, COMDAT
; 36 : ~Two( void ) { a= 0; };
push ebp
mov ebp, esp
sub esp, 68 ; 00000044H
push ebx
push esi
push edi
push ecx
lea edi, DWORD PTR [ebp-68]
mov ecx, 17 ; 00000011H
mov eax, -858993460 ; ccccccccH
rep stosd
pop ecx
mov DWORD PTR _this$[ebp], ecx
mov eax, DWORD PTR _this$[ebp]
mov DWORD PTR [eax], 0
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
[email protected]@[email protected] ENDP ; Two::~Two
_TEXT ENDS
; COMDAT [email protected]@QAEXXZ
_TEXT SEGMENT
_this$ = -4
[email protected]@QAEXXZ PROC NEAR ; Two::`default constructor closure', COMDAT
push ebp
mov ebp, esp
sub esp, 68 ; 00000044H
push ebx
push esi
push edi
push ecx
lea edi, DWORD PTR [ebp-68]
mov ecx, 17 ; 00000011H
mov eax, -858993460 ; ccccccccH
rep stosd
pop ecx
mov DWORD PTR _this$[ebp], ecx
push 0
mov ecx, DWORD PTR _this$[ebp]
call [email protected]@[email protected]@Z ; Two::Two
pop edi
pop esi
pop ebx
add esp, 68 ; 00000044H
cmp ebp, esp
call __chkesp
mov esp, ebp
pop ebp
ret 0
[email protected]@QAEXXZ ENDP ; Two::`default constructor closure'
_TEXT ENDS
; COMDAT [email protected]@[email protected]
_TEXT SEGMENT
___flags$ = 8
_this$ = -4
[email protected]@[email protected] PROC NEAR ; Two::`vector deleting destructor', COMDAT
push ebp
mov ebp, esp
sub esp, 68 ; 00000044H
push ebx
push esi
push edi
push ecx
lea edi, DWORD PTR [ebp-68]
mov ecx, 17 ; 00000011H
mov eax, -858993460 ; ccccccccH
rep stosd
pop ecx
mov DWORD PTR _this$[ebp], ecx
mov eax, DWORD PTR ___flags$[ebp]
and eax, 2
test eax, eax
je SHORT $L281
push OFFSET FLAT:[email protected]@[email protected] ; Two::~Two
mov ecx, DWORD PTR _this$[ebp]
mov edx, DWORD PTR [ecx-4]
push edx
push 4
mov eax, DWORD PTR _this$[ebp]
push eax
call [email protected]@[email protected] ; `eh vector destructor iterator'
mov ecx, DWORD PTR ___flags$[ebp]
and ecx, 1
test ecx, ecx
je SHORT $L282
mov edx, DWORD PTR _this$[ebp]
sub edx, 4
push edx
call [email protected]@Z ; operator delete
add esp, 4
$L282:
mov eax, DWORD PTR _this$[ebp]
sub eax, 4
jmp SHORT $L280
$L281:
mov ecx, DWORD PTR _this$[ebp]
call [email protected]@[email protected] ; Two::~Two
mov eax, DWORD PTR ___flags$[ebp]
and eax, 1
test eax, eax
je SHORT $L284
mov ecx, DWORD PTR _this$[ebp]
push ecx
call [email protected]@Z ; operator delete
add esp, 4
$L284:
mov eax, DWORD PTR _this$[ebp]
$L280:
pop edi
pop esi
pop ebx
add esp, 68 ; 00000044H
cmp ebp, esp
call __chkesp
mov esp, ebp
pop ebp
ret 4
[email protected]@[email protected] ENDP ; Two::`vector deleting destructor'
_TEXT ENDS
; COMDAT [email protected]@[email protected]
_TEXT SEGMENT
___flags$ = 8
_this$ = -4
[email protected]@[email protected] PROC NEAR ; Two::`scalar deleting destructor', COMDAT
push ebp
mov ebp, esp
sub esp, 68 ; 00000044H
push ebx
push esi
push edi
push ecx
lea edi, DWORD PTR [ebp-68]
mov ecx, 17 ; 00000011H
mov eax, -858993460 ; ccccccccH
rep stosd
pop ecx
mov DWORD PTR _this$[ebp], ecx
mov ecx, DWORD PTR _this$[ebp]
call [email protected]@[email protected] ; Two::~Two
mov eax, DWORD PTR ___flags$[ebp]
and eax, 1
test eax, eax
je SHORT $L287
mov ecx, DWORD PTR _this$[ebp]
push ecx
call [email protected]@Z ; operator delete
add esp, 4
$L287:
mov eax, DWORD PTR _this$[ebp]
pop edi
pop esi
pop ebx
add esp, 68 ; 00000044H
cmp ebp, esp
call __chkesp
mov esp, ebp
pop ebp
ret 4
[email protected]@[email protected] ENDP ; Two::`scalar deleting destructor'
_TEXT ENDS
END