使用 std::move 返回时“按右值引用返回”和“按值返回”之间的区别?
Posted
技术标签:
【中文标题】使用 std::move 返回时“按右值引用返回”和“按值返回”之间的区别?【英文标题】:Difference between "return-by-rvalue-ref" & "return-by-value" when you return using std::move? 【发布时间】:2013-05-24 09:47:20 【问题描述】:考虑以下代码:
#include <iostream>
using namespace std;
struct I
I(I&& rv) cout << "I::mvcotr" << endl;
;
struct C
I i;
I&& foo() return move(i) ;
;
int main()
C c;
I i = c.foo();
C 包含 I。而 C::foo() 允许你将 I 移出 C。上面使用的成员函数有什么区别:
I&& foo() return move(i) ; // return rvalue ref
以及以下替换成员函数:
I foo() return move(i) ; // return by value
对我来说,他们似乎在做同样的事情:I i = c.foo();
导致调用I::I(I&&);
。
本例未涵盖的后果是什么?
【问题讨论】:
如果您将其用作I&&i = c.foo()
,您可能会注意到不同之处。如果你在一个临时对象上调用 foo,你可能会遇到麻烦。
很好的例子!非常感谢!
【参考方案1】:
除了考虑您编写的程序是否真正有意义(从数据成员移动很尴尬 - 但好吧,也许有一些用例),在这种情况下,该函数的两个版本最终会做同样的事情。
然而,作为一般惯例,您应该更喜欢按值返回,因为在许多情况下,它允许编译器执行复制省略,并在允许的情况下省略对返回类型的移动构造函数的调用根据 C++11 标准的第 12.8/31 段。
复制省略允许编译器直接在应该从函数的返回值初始化的对象中创建函数的返回值。
因此,作为一般准则,更喜欢按值返回。
【讨论】:
@bmm:这能回答你的问题吗? 代码可能没有意义,但我给出了这个例子,以便 I&& C::foo() 不会返回一个局部变量,这将是一个编译错误。我只是想了解在什么情况下我需要 I&& C::foo() 而 I C::foo() 没有帮助? @bmm:在 99% 的情况下,您根本不需要I&& C::foo()
。只需按值返回。我能想到的唯一有用的 1% 是 std::move()
和 std::forward()
,它们返回右值引用(实际上,后者可能返回左值引用或右值引用,具体取决于模板参数的类型),这样你就可以得到来自左值的右值。但是标准库已经提供了这些,因此您不必自己编写它们。
@bmm:嗯,最后一个总是会出现一些例外的规则或角落用例,所以可能有一些人们可能想要这样做的原因,但实际上,在大多数情况下,这只会使您的程序更加混乱和效率降低(因为它会抑制复制省略)。顺便说一句,如果这有助于回答您的问题,请考虑将答案标记为已接受:)
@AndyProwl:嗯,我现在在文本中到处都看到“右值引用”,要么我第一次错过了它,要么它改变了。我所指的是,无论您返回 I 还是 I&&,在这两种情况下都返回一个右值(I 的右值,I&& 的 x 值)。以上是关于使用 std::move 返回时“按右值引用返回”和“按值返回”之间的区别?的主要内容,如果未能解决你的问题,请参考以下文章
std::move 将 std::string 移动到另一个线程时出错
std :: move和std :: forward之间有什么区别