例如:
Beta_ab&& Beta::toAB() const { return move(Beta_ab(1, 1)); }
这将返回一个悬空引用,就像左值引用一样。函数返回后,临时对象将被销毁。应该按值返回 Beta_ab,如下所示
Beta_ab
Beta_ab Beta::toAB() const { return Beta_ab(1, 1); }
现在,它正确地将一个临时 Beta_ab对象移动到函数的返回值中。如果编译器可以的话,它会通过使用 RVO (返回值优化)来完全避免这种移动。现在,您可以执行以下操作
Beta_ab ab = others.toAB();
它将移动构造到 ab临时,或做 RVO 省略做一个移动或完全复制。我建议你读一读 BoostCon09右值引用101,它解释了这个问题,以及(N) RVO 是如何与之相互作用的。
ab
在其他情况下,返回值引用的情况是一个好主意。假设您有一个 getAB()函数,您经常在临时函数上调用该函数。对于 rvalue 临时值,使其返回常量 lvalue 引用并不是最佳选择。你可以这样实现它
getAB()
struct Beta { Beta_ab ab; Beta_ab const& getAB() const& { return ab; } Beta_ab && getAB() && { return move(ab); } };
请注意,在这种情况下,move不是可选的,因为 ab既不是本地自动的,也不是临时的 rvalue。现在,参考资料限定词&&说第二个函数在 rvalue 临时变量上被调用,执行以下步骤,而不是复制
move
&&
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条。
clang++ -O3
std::min
-O0