一段C++代碼:
//: HowMany_2.cpp#include <iostream>using namespace std;class HowMany { static int objectCount; public: HowMany() { ++objectCount; print("HowMany()"); } ~HowMany() { --objectCount; print("~HowMany()"); } HowMany(const HowMany& h) { ++objectCount; print("HowMany(const HowMany&)"); } void print(const char ss[]) { cout << ss << ": "; cout << "objectCount = " << objectCount << endl; return ; }};int HowMany::objectCount = 0;HowMany f(HowMany x) { x.print("x argument inside f()"); cout << "Return From f()" << endl; return x; // 有傳回值 x}int main() { { HowMany h; cout << "Entering f()" << endl; HowMany h2 = f(h); } return 0;} ///:~
運行結果:
Assembly Code:
38: int main() {39: {40: HowMany h;004017FD lea ecx,[h]; [h] 為對象 h 的記憶體位址00401800 call @ILT+685(HowMany::HowMany) (004012b2); 調用建構函式00401805 mov dword ptr [ebp-4],041: cout << "Entering f()" << endl;0040180C push offset @ILT+200(std::endl) (004010cd)00401811 push offset string "Entering f()" (0046f090)00401816 push offset std::cout (0047ce98)0040181B call @ILT+660(std::operator<<) (00401299); 題外話,觀察一下進棧順序00401820 add esp,800401823 mov ecx,eax00401825 call @ILT+480(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e5)42: HowMany h2 = f(h);0040182A push ecx0040182B mov ecx,esp; 當前 ESP 所指的棧塊作為臨時對象Temp的記憶體位址0040182D mov dword ptr [ebp-18h],esp00401830 lea eax,[h]00401833 push eax; 將h的記憶體位址[h]壓入堆棧00401834 call @ILT+0(HowMany::HowMany) (00401005); 調用拷貝建構函式,把h的內容拷貝到Temp的記憶體中00401839 mov dword ptr [ebp-1Ch],eax0040183C lea ecx,[h2]0040183F push ecx; 將h2的記憶體位址[h2]壓入堆棧00401840 call @ILT+640(f) (00401285); 調用f()函數00401845 add esp,800401848 mov dword ptr [ebp-20h],eax43: }0040184B lea ecx,[h2]0040184E call @ILT+500(HowMany::~HowMany) (004011f9); 調用解構函式,銷毀h200401853 mov dword ptr [ebp-4],0FFFFFFFFh0040185A lea ecx,[h]0040185D call @ILT+500(HowMany::~HowMany) (004011f9); 調用解構函式,銷毀h44: // getchar();45: return 0;00401862 xor eax,eax46: } ///:~
fun()函數的工作機制:
32: HowMany f(HowMany x) {33: x.print("x argument inside f()");004015DB push offset string "x argument inside f()" (0046f030)004015E0 lea ecx,[ebp+0Ch]004015E3 call @ILT+575(HowMany::print) (00401244)34: cout << "Return From f()" << endl;004015E8 push offset @ILT+200(std::endl) (004010cd)004015ED push offset string "Return From f()" (0046f01c)004015F2 push offset std::cout (0047ce98)004015F7 call @ILT+660(std::operator<<) (00401299)004015FC add esp,8004015FF mov ecx,eax00401601 call @ILT+480(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e5)35: return x;00401606 lea eax,[ebp+0Ch]; [ebp+0C]為Temp的記憶體位址00401609 push eax0040160A mov ecx,dword ptr [ebp+8]; [ebp+8]為h2的記憶體位址,ecx指向h2記憶體塊0040160D call @ILT+0(HowMany::HowMany) (00401005); 調用拷貝建構函式,將Temp的內容拷貝到h2的記憶體中00401612 mov ecx,dword ptr [ebp-10h]00401615 or ecx,100401618 mov dword ptr [ebp-10h],ecx0040161B mov byte ptr [ebp-4],00040161F lea ecx,[ebp+0Ch]; ecx儲存Temp的記憶體位址00401622 call @ILT+500(HowMany::~HowMany) (004011f9); 調用解構函式,銷毀Temp00401627 mov eax,dword ptr [ebp+8]; eax儲存h2的記憶體位址36: }
對於運行結果
解析如下:
1. 對象h調用建構函式
2. 輸出字串“Entering f()”
3. 在進入f()函數之前,建立了一個臨時對象Temp,調用拷貝建構函式,將對象h的內容拷貝到Temp中
4. 進入f()函數,在執行“return x”語句後,調用拷貝建構函式,將對象Temp的內容拷貝到h2中(完成了h2 = f(h)的工作)
5. 在f()函數結束前,為Temp調用解構函式,銷毀Temp對象
6. 退出f()函數,在main函數結束前,先銷毀對象h2,最後銷毀對象h
----------------------------------------------------------------------------
逆向分析時執行“HowMany h2 = f(h);”語句過程中棧分布的記錄:
*****
進入f()函數前(建立了一個臨時對象Temp,調用拷貝建構函式,將對象h的內容拷貝到Temp中)
進入f()函數後
*********************************************************
再看<<Thinking in C++>>中的一段代碼,更為清晰的講解了拷貝建構函式的機制:
//: HowMany_2.cpp#include <string>#include <iostream>using namespace std;class HowMany { string name; static int objectCount; public: HowMany(const string& id = "") { name = id; ++objectCount; print("HowMany()"); } ~HowMany() { --objectCount; print("~HowMany()"); } HowMany(const HowMany& h) { name = h.name + "copy"; ++objectCount; print("HowMany(const HowMany&)"); } void print(const string& msg = "") { if (msg.length() != 0) { cout << msg << endl; } cout << '\t' << name << ": " << "objectCount = " << objectCount << endl; return ; }};int HowMany::objectCount = 0;HowMany f(HowMany x) { x.print("x argument inside f()"); cout << "Return From f()" << endl; return x;}int main() { { HowMany h("h"); cout << "Entering f()" << endl; HowMany h2 = f(h); cout << "Call f(), no return value" << endl; f(h); cout << "After call to f()" << endl; } // getchar(); return 0;} ///:~
運行結果:
解釋如下:
1. 建立對象h,並調用建構函式
2. 輸出“Entering f()”字串
3. 進入f()函數前,建立一個臨時對象Temp,並調用拷貝建構函式,將對象h的內容拷貝到Temp中
4. 進入f()函數後,在“return x”時,調用拷貝建構函式,將對象Temp的內容拷貝到h2中,在函數結束前調用解構函式,銷毀對象Temp
5. 輸出字串
6.進入f()函數前,建立一個臨時對象Temp,並調用拷貝建構函式,將對象h的內容拷貝到Temp中
7. 進入f()函數後,建立一個臨時對象x,在“return x”時,調用拷貝建構函式,將對象Temp的內容拷貝到x中,在函數結束前調用解構函式,先銷毀對象Temp,再銷毀對象x
8. 在main函數結束前,調用解構函式,先銷毀對象h2,再銷毀對象h