您的位置:首页 > 编程语言 > C语言/C++

C++编译器优化之RVO

2020-09-05 18:22 633 查看

写这篇文章纯属意外收获.
先看一段代码:
在这段代码中定义了构造函数,拷贝构造函数,移动构造函数,赋值构造,移动赋值构造,以及析构函数.

#include <iostream>

using namespace std;

class A
{
public:
A() {
cout << "constructor\n" <<flush;
}

A(const A &a) {
cout << "copy constructor\n"<<flush;
}

A(A &&a) {
cout << "move constructor\n" <<flush;
}

A &operator=(const A &a)
{
cout << "copy assignment constructor\n" <<flush;
if (this == &a)
{
return *this;
}
else
{
this->i = a.i;
}
return *this;
}
A &operator=(A &&a) {
cout << "move assignment constructor\n" <<flush;
return *this;
}

~A(){ cout<<"destructor\n"<<flush;}

private:
int i;
};

inline A foo(){
return A();
}

int main() {
auto x=foo();
return 0;
}

此处在以前我可能会分析这段代码效率会很低,调用了1次构造函数,2次移动拷贝构造函数,三次析构函数.
具体流程为,

  • 1.执行foo函数,

    return A();

    2.
    A()
    调用构造函数生成中间对象(是一个右值),
    3.执行移动构造函数生成返回值,
    4.析构中间对象
    5.调用移动构造函数生成x对象
    6.析构返回值对象
    7.析构x对象,程序结束.

Maybe,部分人还有其他答案,但是把这段代码编译执行看看结果呢?

➜ g++ main.cpp -std=c++11
➜ ./a.out
constructor
destructor

哈哈,**居然只调用了一次构造,一次析构?**是我错了?居然比我想想的简单高校很多,这是为何

程序逻辑上来说,上面的几次构造与析构没问题,只是编译的时候编译器进行了RVO优化.换一种编译方式可验证我们的分析

➜ g++ main.cpp -std=c++11 -fno-elide-constructors
➜ ./a.out
constructor
move constructor
destructor
move constructor
destructor
move constructor
destructor
destructor

何谓RVO优化

RVO 即 “Return Value Optimization”,是一种编译器优化技术,通过该技术编译器可以减少函数返回时生成临时值值(对象)的个数,可以提高程序的运行效率,对需要分配大量内存的类对象其值复制过程十分友好。

在 C++11 标准中我们可以看到关于该优化标准的更多信息。标准中规定,在以下两种环境下,要求编译器省略类对象的复制和移动构造,即使复制/移动构造函数和析构函数拥有可观察副作用。RVO优化直接将对象构造到它们本来要复制/移动到的存储中。只要语言确保不发生复制/移动操作,复制/移动构造函数就不必存在或可访问,即使在概念上。这两种环境分别是:

  • 在 “return” 语句中,当操作数为与函数返回类型为同一类类型的纯右值时;
  • 在变量的初始化中,当初始化器表达式为与变量类型为同一类类型的纯右值时:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: