例如:
Beta_ab&& Beta::toAB() const {
return move(Beta_ab(1, 1));
}
Beta_ab&& Beta::toAB() const {
return move(Beta_ab(1, 1));
}
Beta_ab&&
Beta::toAB() const {
return move(Beta_ab(1, 1));
}
这将返回一个悬空引用,就像对于左值引用的情况一样。函数返回后,临时对象将被销毁。你应该通过值来返回 Beta_ab
,就像以下代码:
Beta_ab
Beta::toAB() const {
return Beta_ab(1, 1);
}
现在,它将一个临时的Beta_ab
对象正确地移动到函数的返回值中。如果编译器可以的话,它将通过使用RVO(返回值优化)避免完全移动。现在,您可以执行以下操作:
Beta_ab ab = others.toAB();
它将移动构造临时对象到ab
中,或者通过返回值优化(RVO)来完全省略移动或复制。我建议你阅读BoostCon09 Rvalue References 101了解这个问题以及(N)RVO如何与之交互。
在其他情况下,返回rvalue引用是一个好主意。设想你有一个getAB()
函数,你经常在临时对象上调用它。将其返回为常量左值引用并不是最优的选择。你可以这样实现:
struct Beta {
Beta_ab ab;
Beta_ab const& getAB() const& { return ab; }
Beta_ab && getAB() && { return move(ab); }
};
请注意,此处的move
不是可选项,因为ab
既不是局部自动变量也不是临时rvalue。现在,ref-qualifier &&
表示第二个函数在rvalue临时对象上调用,执行移动操作而不是复制。Beta_ab ab = Beta().getAB();
它可以更有效率,例如,在稍微不同的上下文中:
template <typename T>
T&& min_(T&& a, T &&b) {
return std::move(a < b? a: b);
}
int main() {
const std::string s = min_(std::string("A"), std::string("B"));
fprintf(stderr, "min: %s\n", s.c_str());
return 0;
}
clang++ -O3
为上述代码生成了54条指令,而对于常规的std::min
则生成了62条指令。然而,使用-O0
,上述代码生成了518条指令,而常规的std::min
则生成了481条指令。for(:)
中使用了临时对象的引用,并对已释放的对象进行了整合。修复方法:https://ideone.com/tQVOal - wonder.micestd::move()
只是用作显式转换,以更清晰地说明这一点。这不是你会复制粘贴到你的项目中的代码。它并不与得票最高的答案相矛盾,因为在函数内部创建了临时对象。在这里,返回的对象是其中一个参数(临时对象在评估包含它们被创建的点的完整表达式的最后一步中被销毁)。 - wonder.mice