在C ++中使用临时值时的返回值优化(RVO)

时间:2012-03-12 18:38:29

标签: c++ c++11

假设我有两个功能A和B.

其中函数A返回对象X,函数B将对象X作为参数。例如。

X A() {
    X x;
    return x;
}

void B(X x) {
    write(x.data, x.size);
}

int main() { B(A()); }

此对象X是否仅使用RVO构造一次作为B的临时对象,或者我是否需要使用移动语义。

4 个答案:

答案 0 :(得分:3)

编译器只允许允许执行RVO,但标准没有义务。因此,它可能会也可能不会优化您的代码,完全取决于所使用的编译器及其参数。

另一个问题可能对相关细节有所帮助:When should RVO kick-in?

答案 1 :(得分:2)

如果使用复制省略,则X只会被构造一次。

即使禁用了复制省略(例如将-fno-elide-constructors传递给gcc),也会自动使用移动构造函数。

您可以自己想象它:

#include <cstdio>

struct X
{
    X() { printf("default constructed\n"); }
    ~X() { printf("destructed\n"); }
    X(const X&) { printf("copy constructed\n"); }
    X(X&&) { printf("move constructed\n"); }
};

X A() {
    X x;
    return x;
}

void B(X x) {

}

int main() {
    B(A());
}

使用RVO打印

default constructed
destructed

没有RVO打印

default constructed
move constructed
destructed
move constructed
destructed
destructed

答案 2 :(得分:1)

它很可能是同一个对象(即不会创建额外的副本)。这不是RVO,它被称为复制省略。

引用不是来自C ++ 11,而是来自C ++ 03:

12.2 / 2临时对象

  

这里,一个实现可能会使用一个临时构造X(2),然后使用X的copy-constructor将它传递给f();或者,X(2)可以在用于保存参数的空间中构造。 /.../

答案 3 :(得分:0)

我建议您只使用您感兴趣的编译器进行测试 - 例如,定义X的复制构造函数以产生一些副作用(例如打印消息),并查看您给出的代码对您的代码有何影响编译器使用您首选的优化设置。

相关问题