一段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],0 41: 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,8 00401823 mov ecx,eax 00401825 call @ILT+480(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e5) 42: HowMany h2 = f(h); 0040182A push ecx 0040182B mov ecx,esp ; 当前 ESP 所指的栈块作为临时对象Temp的内存地址 0040182D mov dword ptr [ebp-18h],esp 00401830 lea eax,[h] 00401833 push eax ; 将h的内存地址[h]压入堆栈 00401834 call @ILT+0(HowMany::HowMany) (00401005) ; 调用拷贝构造函数,把h的内容拷贝到Temp的内存中 00401839 mov dword ptr [ebp-1Ch],eax 0040183C lea ecx,[h2] 0040183F push ecx ; 将h2的内存地址[h2]压入堆栈 00401840 call @ILT+640(f) (00401285) ; 调用f()函数 00401845 add esp,8 00401848 mov dword ptr [ebp-20h],eax 43: } 0040184B lea ecx,[h2] 0040184E call @ILT+500(HowMany::~HowMany) (004011f9) ; 调用析构函数,销毁h2 00401853 mov dword ptr [ebp-4],0FFFFFFFFh 0040185A lea ecx,[h] 0040185D call @ILT+500(HowMany::~HowMany) (004011f9) ; 调用析构函数,销毁h 44: // getchar(); 45: return 0; 00401862 xor eax,eax 46: } ///:~
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,8 004015FF mov ecx,eax 00401601 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 eax 0040160A 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,1 00401618 mov dword ptr [ebp-10h],ecx 0040161B mov byte ptr [ebp-4],0 0040161F lea ecx,[ebp+0Ch] ; ecx保存Temp的内存地址 00401622 call @ILT+500(HowMany::~HowMany) (004011f9) ; 调用析构函数,销毁Temp 00401627 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