使用右值引用返回是否更高效?

160
例如:
Beta_ab&& Beta::toAB() const {
    return move(Beta_ab(1, 1));
}
2个回答

308
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();

71
在返回类型为右值引用时,我一直认为悬空引用问题会自动解决。很高兴在问题出现之前搞清楚了。栈溢出的错误很糟糕。 - deft_code
34
实际上,右值引用就像左值引用一样只是“引用”,它们不会复制或存储任何内容。 - Johannes Schaub - litb
11
成员函数上的const &限定符比简单的const有什么不同? - galinette
4
+1-ed,但链接已损坏:BoostCon09右值引用101 - Siu Ching Pong -Asuka Kenji-
3
这是限定符的内容。 - Malcolm
显示剩余17条评论

-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条指令,而对于常规的std::min则生成了62条指令。然而,使用-O0,上述代码生成了518条指令,而常规的std::min则生成了481条指令。

我对你的回答感到困惑。我曾尝试过类似(或许是相同的)的版本,但失败了:https://ideone.com/4GyUbZ 你能解释一下为什么吗? - Deqing
你在 for(:) 中使用了临时对象的引用,并对已释放的对象进行了整合。修复方法:https://ideone.com/tQVOal - wonder.mice
20
这个答案实际上是错误的吗?对于模板参数T,T&&不是右值引用,而是通用引用。因此,在这种情况下,我们应该始终调用std::forward<T>,而不是std::move!更何况,这个答案直接与上面得到最多赞的答案相矛盾。 - xdavidliu
2
@xdavidliu 这个答案是一个人为的例子,说明通过返回rvalue可以更有效率。std::move()只是用作显式转换,以更清晰地说明这一点。这不是你会复制粘贴到你的项目中的代码。它并不与得票最高的答案相矛盾,因为在函数内部创建了临时对象。在这里,返回的对象是其中一个参数(临时对象在评估包含它们被创建的点的完整表达式的最后一步中被销毁)。 - wonder.mice
9
@wonder.mice,请将 T 替换为 std::string;这里根本不需要使用模板,而且使用 T&& 作为右值引用只是一种糟糕的风格,会让新手在模板和右值方面感到不必要的困惑。 - xdavidliu
我对这里有这么多人没有理解到重点感到惊讶。这不是关于风格或教人如何编写代码的问题。这只是一个例子,用来说明一个非常具体的观点 - 通过返回右值引用是否可以提高性能。我扩展了答案,加入了更多细节。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接