通过右值引用返回是否更有效?


Answers:


246
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如何与之交互。


在其他情况下,您返回右值引用的情况将是一个好主意。假设您有一个getAB()经常在临时函数上调用的函数。使它返回右值临时对象的const左值引用并不是最佳选择。您可以这样实现

struct Beta {
  Beta_ab ab;
  Beta_ab const& getAB() const& { return ab; }
  Beta_ab && getAB() && { return move(ab); }
};

请注意,move在这种情况下不是可选的,因为ab它既不是本地自动值也不是临时右值。现在,ref-qualifier &&表示在rvalue临时对象上调用了第二个函数,进行了以下移动,而不是复制

Beta_ab ab = Beta().getAB();

51
我一直认为,当返回类型是r值参考时,悬空参考问题会自动消失。很高兴我在咬伤之前弄清了问题。堆栈粉碎错误很烂。
deft_code

31
:)实际上,右值引用就像“左值”引用一样,都是“正义引用”。他们不复制或存储任何东西。
Johannes Schaub-litb

9
成员上的const&qualifier比简单的const还具有什么功能?
galinette 2014年

4
+1版本,但链接断开:BoostCon09 Rvalue参考101
小清庞-明日香贤治

3
@galinette这些是ref限定词
Malcolm

2

例如,在有些不同的情况下,它可以更有效:

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条指令,而常规代码则生成62条指令std::min。但是,-O0对于上面的代码,它生成518条指令,而对于常规代码,则生成481条指令std::min


您的回答让我感到困惑。曾经尝试过类似的(也许)版本,但是失败了:ideone.com/4GyUbZ您能解释为什么吗?
德庆'18

您在临时对象中使用了引用,for(:)并在已释放对象上进行了集成。修复:ideone.com/tQVOal
wonder.mice

3
这个答案真的不对吗?对于模板参数T,T && 不是 r值引用,而是通用引用,在这种情况下,我们应该始终调用std :: forward <T>,而不是 std :: move!更不用说,这个答案与上面投票最多的答案直接矛盾。
xdavidliu

@xdavidliu这个答案是一个人为的例子,说明如何通过右值返回更有效。std::move()仅用作显式表述,以更清楚地说明这一点。这不是您要复制粘贴到项目中的代码。它与最高投票答案没有矛盾,因为在函数内部创建了临时对象。这里返回的对象是参数之一(临时对象在评估(按词法包含)创建点的完整表达式的最后一步中被销毁)。
wonder.mice

2
@ wonder.mice,然后将T替换为std :: string; 这里完全不需要使用模板,而将T &&作为r值引用只是一种糟糕的样式,不必要地使刚接触模板和r值的人感到困惑。
xdavidliu
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.