出自《程序员的自我修养-链接、装载与库》P299
eax是函数传递返回值的一个通道。
1.对于小于4个字节的数据函数将返回值存储在eax中。
2.5~8个字节对象的情况调用惯例都是采用eax和edx的联合返回方式进行。
3.大于8个字节的返回类型,用一下代码测试:
1 typedef struct big_thing 2 { 3 char buf[128]; 4 }big_thing; 5 6 big_thing return_test() 7 { 8 big_thing b; 9 b.buf[] = 0;10 return b;11 }12 13 int main()14 {15 big_thing n = return_test();
16 }
如果返回值的类型的尺寸太大,c语言在函数的返回时会使用一个临时的栈上内存作为中转,结果返回值对象会被拷贝两次。因而不到万不得已,不要轻易返回大尺寸对象。
再来看看函数返回一个C++对象会如何:
1 #include <iostream> 2 using namespace std; 3 4 struct cpp_obj 5 { 6 cpp_obj() 7 { 8 cout << "ctor\n"; 9 }10 11 cpp_obj(const cpp_obj& c)12 {13 cout << "copy ctor\n";14 }15 16 cpp_obj& opearator=(const cpp_obj& rhs)17 {18 cout << "operator = \n";19 return *this;20 }21 22 ~cpp_obj()23 {24 cout << "dtor\n";25 }26 };27 28 cpp_obj return_test()29 {30 cpp_obj b;31 cout << "before return\n";32 return b;33 }34 int main()35 {36 cpp_obj n;37 n = return_test();
38 }
运行后的输出结果可以得出:函数返回之后,进行了一个拷贝函数的调用,以及一次operator=的调用,也就是说,仍然产生了两次拷贝。因此C++的对象同样会产生临时对象。
在这段代码中我们还能看到在c++返回一个对象时,对象要经过两次拷贝构造函数的调用才能够完成返回对象的传递,1次拷贝到栈上的临时对象里,另一次把临时对象拷贝到存储返回值的对象里。在某些编译器里,返回一个对象甚至要经过更多的步骤。
为了减少返回对象的开销,C++提出了返回值优化(RVO)技术,可以将某些场合下的对象拷贝减少一次,例如:
1 cpp_obj return_test()2 {3 return cpp_obj();4 }
目的是直接将对象的构造在传出时使用的临时对象上,减少一次复制过程。
联系客服