假设我有两个函数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的复制构造函数以产生一些副作用(例如打印消息),并查看您提供的代码使用您喜欢的优化设置对编译器做了什么。