C++构造函数的优化

下面这段代码

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对象析构

然而,当我们实际编译并运行它时,运行结果为

1
2
default ctor
dtor

发现所有的拷贝构造和临时对象的析构都被优化掉了。这就是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
ctor with int
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.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×