下面这段代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <iostream> using namespace std ;class A { public : A() { cout << "default ctor\n" ; } A(const A& b) { cout << "copy ctor\n" ; } ~A() { cout << "dtor\n" ; } }; A foo () { A b; return b; } int main () { A a = foo(); return 0 ; }
理论上,它的运行结果应为
1 2 3 4 5 6 default ctor // foo函数第一行的对象b的构造 copy ctor // 对象b拷贝到返回值临时对象 dtor // 对象b析构 copy ctor // 返回值临时对象拷贝到main中对象a dtor // 返回值临时对象析构 dtor // main对象析构
然而,当我们实际编译并运行它时,运行结果为
发现所有的拷贝构造和临时对象的析构都被优化掉了。这就是NRV优化 带来的性能上的好处。
对下面这个代码也是同理的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <iostream> using namespace std ;class A { public : A() { cout << "default ctor\n" ; } A(int x) { cout << "ctor with int\n" ; } A(const A& b) { cout << "copy ctor\n" ; } ~A() { cout << "dtor\n" ; } }; int main () { A a = 3 ; return 0 ; }
优化前
1 2 3 4 ctor with int copy ctor dtor dtor
优化后
值得一提的是,对于上面这一段代码,若使用括号(而不是等号)进行初始化,则无论是否开启优化都不会有临时对象的产生。即如下写法不会构造临时对象。
1 2 3 4 5 6 class A { ... }; int main () { A a (3 ) ; return 0 ; }
使用g++编译器我们可以加上 -fno-elide-constructors
参数,如此将关闭掉编译器对构造函数的优化,并输出未优化时的结果。
可以在 man g++
中查到对该参数的描述。
1 2 3 4 -fno-elide-constructors The C++ standard allows an implementation to omit creating a temporary that is only used to initialize another object of the same type. Specifying this option disables that optimization, and forces G++ to call the copy constructor in all cases.