Skip to content

Return Value Optimization

在函数返回值的传递过程中,可能会触发多次对象的拷贝构造或移动操作。为了减少这些不必要的拷贝,C++ 编译器会采用一些优化技术,如 拷贝省略 (1)、返回值优化 (2)和 命名返回值优化 (3)。

  1. Copy Elision
  2. Return Value Optimization,RVO
  3. Named Return Value Optimization,NRVO

RVO和NRVO的启用条件

RVO 和 NRVO 是编译器自动完成的优化,但是这些优化并不总是启用,具体取决于编译器的实现和配置

在 C++17 之前,RVO 是一个可选优化,但在 C++17 标准之后,RVO 被强制启用,编译器必须在符合条件的情况下执行拷贝省略。

NRVO 通常依赖于编译器的智能分析,虽然大多数现代编译器都能支持 NRVO,但其效果和激进程度因编译器和版本的不同而有所差异。

按值传递和拷贝省略

不具名返回值优化

不具名返回值优化发生在返回一个无名对象或者临时对象,,一般是 Return 语句中直接创建并返回的对象。

URVO 从 C++98 开始已被许可,但是一直到 C++17 编译器才强制返回值优化。

无返回值优化
Data GetData()  
{  
    return Data{};  // ctro1  
                    // copy ctor2, dtor1  
}

int main()
{
    Data d = GetData(); // copy ctor3, dtor2
    return 0;           
                        // dtor3
}
对象发生多次拷贝。

其中第三次拷贝和赋值右值相关。

有返回值优化
Data GetData()  
{  
    return Data{};  // ctro1  
}

int main()
{
    Data d = GetData(); 
    return 0;           
                        // dtor1
}
对象只被构造一次。

具名返回值优化

具名返回值优化一般发生在返回一个已经创建的对象。

MSVC默认不开启具名返回值优化,如果需要开启优化,需要在 /O2 下编译。

容器返回值优化

对于容器来说,若整个容器发生拷贝,代价很高。

因此,非常有必要考虑返回值优化。C++17 开始,强制对容器进行返回值优化。

容器返回值优化
std::vector<Data> GetDataContainers() {
    //!!! case 1
    // return std::vector<Data>{Data{}};    // ctor 1, copy ctor 2, dtor 1

    //!!! case 2
    std::vector<Data> vec{Data{}};          // ctor 1, copy ctor 2, dtor 1
    return vec;
}                                          

int main() {
    auto d = GetDataContainers();    
    return 0;
}                                           // dtor 2

Reference