生活随笔
收集整理的這篇文章主要介紹了
用汇编的眼光看C++(之拷贝、赋值函数)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
拷貝構造函數和復制函數是類里面比較重要的兩個函數。兩者有什么區別呢?其實也很簡單,我們可以舉個例子,加入有這樣一個類的定義:
[cpp]?view plaincopy
class?apple?? {?? public:?? ????apple()?{??printf("apple()!\n");}?? ????apple(apple&?a)?{??printf("copy?apple()!\n");}?? ????apple&?operator=(apple&?a)?{??printf("=?apple()\n");?return?*this;}?? ????~apple()?{??printf("~apple()!\n");}?? ????void?print()?const?{??return;}?? };??
?? ?那么我們在如下的函數里面進行調用的時候,調用的函數分別是哪些呢?
[cpp]?view plaincopy
void?process()?? {?? ????apple?a,?c;?? ????apple?b?=a;?? ????c?=?b;?? }?? ?? ?其實匯編的結果是這樣的,大家可以一起看一下,自己嘗試讀一下。如果一次不是很明白,可以多讀幾次。
[cpp]?view plaincopy
70:???????apple?a,?c;?? 0040127D???lea?????????ecx,[ebp-10h]?? 00401280???call????????@ILT+70(apple::apple)?(0040104b)?? 00401285???mov?????????dword?ptr?[ebp-4],0?? 0040128C???lea?????????ecx,[ebp-14h]?? 0040128F???call????????@ILT+70(apple::apple)?(0040104b)?? 00401294???mov?????????byte?ptr?[ebp-4],1?? 71:???????apple?b?=a;?? 00401298???lea?????????eax,[ebp-10h]?? 0040129B???push????????eax?? 0040129C???lea?????????ecx,[ebp-18h]?? 0040129F???call????????@ILT+50(apple::apple)?(00401037)?? 004012A4???mov?????????byte?ptr?[ebp-4],2?? 72:???????c?=?b;?? 004012A8???lea?????????ecx,[ebp-18h]?? 004012AB???push????????ecx?? 004012AC???lea?????????ecx,[ebp-14h]?? 004012AF???call????????@ILT+75(apple::operator=)?(00401050)?? 73:???}?? 004012B4???mov?????????byte?ptr?[ebp-4],1?? 004012B8???lea?????????ecx,[ebp-18h]?? 004012BB???call????????@ILT+0(apple::~apple)?(00401005)?? 004012C0???mov?????????byte?ptr?[ebp-4],0?? 004012C4???lea?????????ecx,[ebp-14h]?? 004012C7???call????????@ILT+0(apple::~apple)?(00401005)?? 004012CC???mov?????????dword?ptr?[ebp-4],0FFFFFFFFh?? 004012D3???lea?????????ecx,[ebp-10h]?? 004012D6???call????????@ILT+0(apple::~apple)?(00401005)?? 004012DB???mov?????????ecx,dword?ptr?[ebp-0Ch]?? 004012DE???mov?????????dword?ptr?fs:[0],ecx?? 004012E5???pop?????????edi?? 004012E6???pop?????????esi?? 004012E7???pop?????????ebx?? 004012E8???add?????????esp,58h?? 004012EB???cmp?????????ebp,esp?? 004012ED???call????????__chkesp?(004087c0)?? 004012F2???mov?????????esp,ebp?? 004012F4???pop?????????ebp?? 004012F5???ret?? ?? ?代碼有點長,大家可以一句一句來看,比如說就按照70、71、72、73分別查看對應的匯編代碼:
?? ?(1)70句: 我們看到函數做了兩次函數調用,恰好就是apple的構造函數調用。這也正好對應著兩個臨時變量a和c,兩個變量的地址分別是【ebp-10】和【ebp-14】,這里也可以看出整個類的大小就是4個字節,就是一塊存放數據的普通內存。而構造函數之所以能和對應的內存綁定在一起,主要是因為ecx記錄了內存的起始地址,這在C++編譯中是十分關鍵的。我們看到的C++構造函數好像是沒有綁定內存,實際上在VC里面已經做好了約定,ecx就是this指針,就是類的內存起始地址。有興趣的同學看看G++編譯的時候,采用的this指針是哪個寄存器保存的?(其實是eax)
?? ?(2)71句:通過對應看到了eax記錄了引用變量的地址,而ecx是ebp下面緊挨著四個字節。但是函數調用的地址和前面的缺省構造函數不太一樣,所以我們大膽猜測,這里的構造函數這是拷貝構造函數,我們可以在調試的時候查看一下打印消息。
?? ?(3)72句:0x4012AF語句已經清楚地告訴了我們,這里調用的函數就是operator=函數,這一部分是算術符重載的內容,我們在后面的博客會重點介紹。
?? ?(4)73句: 前面我們講過,析構函數在函數調用結束的時候被被自動調用,那么這里我們看到卻是出現了三個調用?這三個變量正好是我們之前說的a、b、c三個變量。那么這三個變量調用的次序是怎樣的呢?我們可以查看一下變量的地址,分別是【ebp-18h】、【ebp-14h】、【ebp-10h】,這正好和變量出現的順序相反。所以我們看到,析構函數和構造函數是嚴格一一對應的,誰先出現,誰后析構。
【預告: 下面的博客我們會對構造、析構中出現的一些現象進行總結】
總結
以上是生活随笔為你收集整理的用汇编的眼光看C++(之拷贝、赋值函数)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。