C++primer上说:
“直接初始化和复制初始化。复制初始化使用=符号,而直接初始化将初始化式放在圆括号中。
当用于类类型对象时,初始化的复制形式和直接形式有所不同:直接初始化直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象(7.3.2节),然后使用复制构造函数将那个临时对象复制到正在创建的对象:
string null_book = "9-999-99999-9 ";//copy-initialization
string dots(10, '. ');//direct-initialization
string empty_copy = string();//copy-initialization
string empty_direct;//direct-initialization
对于类类型对象,只有指定单个实参或显式创建一个临时对象用于复制时,才使用复制初始化。
创建dots时,调用参数为一个数量和一个字符的string构造函数并直接初始化dots的成员。创建null_book时,编译器首先调用接受一个C风格字符串形参的string构造函数,创建一个临时对象,然后,编译器使用string复制构造函数将null_book初始化为那个临时对象的副本。
empty_copy和empty_direct的初始化都调用默认构造函数。对前者初始化时,默认构造函数创建一个临时对象,然后复制构造函数用该对象初始化empty_copy。对后者初始化时,直接运行empty_direct的默认构造函数”
请看下面的例子:
#include <iostream> #include <cstdlib> using namespace std; class A { public: A(){cout << "constructor called!" << endl;} A(int i) : x(i){cout << i << " constructor called!" << endl;} A(const A &a){cout << x << " copy constructor called!" << endl;} ~A(){cout << x << " destructor called" << endl;} private: //A(const A &a){cout << "copy constuctor called!" << endl;} int x; }; A get_A() { A a(5); return a; } int main() { A a = 1;system("pause"); // 1 A b = get_A();system("pause"); // 2 b = a;system("pause"); // 3 A c = A(2);system("pause"); // 4 b = 3;system("pause"); // 5 A d = b;system("pause"); // 6 return 0; }
在CB中编译运行结果:
按照B.Lippman的说法, 显示的结果应该不是这个样子的, 但是编译器有优化, 跳过了有些不必要的复制构造函数的调用, 现在说说我的理解, 不知道对不对, 希望大家都说说自己的看法, 谢谢!
第1句, 生成了临时对象, 但是编译器优化,跳过了复制构造函数。
第2句, 在VS中的运行结果是这样的:
当从函数返回该类型的对象时, 调用复制构造函数, VS中是正常应该出现的结果, 但是CB中却没有, 我猜是g++优化的比VS好吧。
第3句, 调用的是编译器默认生成的赋值操作符(=), 大概应该是这样的:
void operator = (const A &a) { x = a.x; }
第4句, 和第一句差不多, 我猜第1句A a = 1等效于A a = A(1).
第5句, 先生成临时对象, 然后再调用编译器生成的赋值操作符(=)。
第6句, 从结果显示只调用了复制构造函数, 到底有没有临时对象生成, 请大家说说自己的看法。
另外, 我把get_A函数换成了如下形式:
A get_A() { return A(5); }
在VS中的显示结果:
我很疑问, 复制构造函数怎么没有被调用?难道又是编译器的优化? 请大家给我解释解释, 谢谢!
我想是应该会优化的,
A get_A() { A a(5); return a; }
这种写法中,因为a在栈上,函数结束时,需要析构,所以必须copy construct成另外一个对象返回。
A get_A() { return A(5); }
这种写法中,编译器应该就可以大胆地直接把构造出来的对象返回了。所以真的可能是一种优化。
Google了一下,还真有,http://en.wikipedia.org/wiki/Return_value_optimization
楼主真是个细心人啊。
谢谢你的回复!但是,
A get_A() { A a(5); return a; }
这种写法在CB中, 从结果上看没有调用复制构造函数, 这是为什么呢?g++优化能力很犀利?
@wj@wust: 这个真不清楚了,标准里没有规定编译器应该怎么返回,只要返回正确的值就行,
也许可以反汇编一下,看看生成的二进制代码。