1. 介绍

拷贝消除和返回值优化其实并不是一个统一的标准的行为,

主要还是看编译器自身的行为和相应的C++版本。

了解这一点的目的主要是要明白,编译器会做出的行为。

2. 举例

直接上代码分析

#include <iostream>
#include <vector>


class Foo {
public:
    Foo() = default;

    Foo(const Foo &a) {
        std::cout << "copy constructor" << '\n';
    }

    void operator=(const Foo &a) {
        if ( this != &a) {
            std::cout << "assign op\n"; 

        }
    }

};

Foo rvo()
{
    return Foo{};
}

Foo nrvo()
{
    Foo s{};
    return s;
}

// disable copy ellision
// -fno-elide-constructors

// g++ -fno-elid-constructors  -O0 -std=c++11

int main()
{

    std::cout << "init f1\n";
    Foo f1 { rvo() };

    std::cout << "init f2\n";

    Foo f2{ nrvo() };
    return 0;
}

如果我们不考虑任何的拷贝优化,

这个程序会调用四次copy constructor

对于每个对象来说都是两次拷贝:

第一次是从函数的局部变量到返回值,

第二次是从返回值再到变量的构造。

对于f1来说,第一次拷贝发生在rvo()返回main;

第二次拷贝发生在rvo()的返回值去初始化f1

对于f2来说,第一次拷贝发生在nrvo返加值smain

第二次拷贝发生在用nrvo()的返回值去初始化f2

而在开启优化后,gcc可以将这四次拷贝全都优化掉!!!

msvc在禁用优化选项开启时,也就是/Od选项,可以优化掉

三次拷贝,猜测是有名对象返回值那次拷贝没有优化掉。

当开启优化选项时,四次拷贝也全都被优化掉了。

gcc可以通过-fno-elide-constructos来禁用掉优化,

从而观察未优化前的拷贝次数。

3. 参考

learncpp-copy-elision

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐