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



假设我有两个函数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的临时对象只构造一次,还是我需要使用移动语义。

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

另一个问题可能有助于了解相关细节:RVO应该何时开始?

如果使用了复制省略,X将只构造一次。

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

你可以自己想象:

#include <cstdio>
struct X
{
    X() { printf("default constructedn"); }
    ~X() { printf("destructedn"); }
    X(const X&) { printf("copy constructedn"); }
    X(X&&) { printf("move constructedn"); }
};
X A() {
    X x;
    return x;
}
void B(X x) {
}
int main() {
    B(A());
}

使用RVO打印

默认构造已销毁

在没有RVO的情况下,它会打印

默认构造移动构造已销毁移动构造已销毁已销毁

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

报价不是来自C++11,而是来自C++03:

12.2/2临时物体

在这里,一个实现可能使用一个临时的方法来构造X(2),然后使用X的复制构造函数将其传递给f();或者,X(2)可以在用于容纳自变量的空间中构造。/…/

我建议您只需使用您感兴趣的任何编译器来测试它——即,定义X的复制构造函数以产生一些副作用(例如打印消息),并查看您提供的代码使用您喜欢的优化设置对编译器做了什么。

最新更新