我想我理解带有签名的函数,比如:
void f(std::string&&):
它将应用于右值以重用其资源。但是,我偶尔会看到这样的代码:
std::string t();
std::string&& s = t();
其中变量初始化为右值ref。(这里我写了t来返回值,但如果通过l/rvalue引用返回时的行为不同,请有兴趣知道)。
通常,我在关于C++的帖子/谜题中看到这一点,而不是生产代码。
我有几件事想了解一下
1.这种行为的规则是什么?
1.与通过值或左值常量引用捕获相比,这给你带来了什么好处?在我看来,如果你通过值捕获,移动/复制将被省略,你将能够修改它(不像const-ref)。我可能是不正确的,但如果是这样的话,我看不出什么好处右值引用将在这里
1.当t返回一个右值引用时,它的行为是否不同?返回右值引用的好理由是什么?我猜std::move可以,但它还有什么好处呢?
2条答案
按热度按时间ssm49v7z1#
右值引用可以绑定到两个对象:
如果您不熟悉价值类别或需要快速复习,这里有一个快速概述:
| | movable | immovable |
| --|--| ------------ |
| xvalue -
std::move(x)
等。|左值-x
、"str"
等||| prvalue -
1 + 2
、sqrt(2)
等。|||Rvalue引用xvalues
在这种情况下,我们只是将引用绑定到其他对象。如果我们使用
a
,b
或c
,它们在大多数上下文中都是左值,与std::string&
这样的左值引用相比几乎没有区别。然而,该类型携带
a
、b
和c
引用可移动的东西的信息,我们可以使用std::move
或std::forward
将引用转换回x值。这将允许传递引用,然后稍后调用移动构造函数。返回右值引用
当从函数返回右值引用时(例如
std::move
),它会变成一个xvalue。这就是大多数情况下创建右值对x值的引用的方式。下面是几个例子:std::forward
有时会返回右值引用,如果它是用右值调用的std::move_iterator
有一个*
运算符,它返回一个右值引用std::get(std::tuple)
在元组是右值时返回对元组成员的右值引用右值对纯右值的引用
在本例中,我们引用
t()
返回的临时对象。这段代码乍看起来是错误的,但实际上是有效的,因为临时对象的生存期扩展到了r
的范围。临时实体化是因为它使泛型编程更容易。我们经常在使用转发引用时创建右值引用(例如
auto&&
)。如果没有临时物化,当
e
初始化为纯右值时,这段代码将具有未定义的行为,因为我们将立即创建一个悬空引用。在这个用例之外,它没有任何意义,因为具体化并不比仅仅存储对象好。物化实际上对性能来说更糟糕(见下文)。压缩
请注意,通过右值引用实现右值并不能使我们的代码更快;这不是优化技巧。如果可能的话,最好只传递纯右值。例如:
像这样的例子就是为什么你不具体化临时值,如果你不需要。创建右值引用是出于必要,而不是因为它可以提高性能或代码质量。
des4xlb02#
1.这种行为的规则是什么?
如果
t
按值返回,您将获得返回的任何内容的副本(尽管副本可能被省略)。右值引用延长了该副本的生存期,但与普通变量相比没有任何好处。See also。如果
t
通过左值引用返回,则代码无法编译,因为右值引用无法绑定到它。如果
t
通过右值引用返回,您将获得对返回内容的引用。如果t
返回一个局部变量,那么您将得到一个悬空引用,因为该变量在调用之后就消失了。否则,您得到的引用的行为或多或少类似于左值引用,就好像t
是由左值引用返回的。1.与通过值或左值常量引用捕获相比,这给你带来了什么好处?在我看来,如果你通过值捕获,移动/复制将被省略,你将能够修改它(不像const-ref)。我可能是不正确的,但如果是这样的话,我看不出什么好处右值引用将在这里
不要将lambda表达式中使用的“捕获”与函数调用的简单赋值过程相混淆。Copy (and move) elision仅在函数返回局部变量(或局部表达式)时适用。如果
t
返回其他内容,例如解引用某个内容所产生的值,或t
外部的其他对象的成员变量,则不可能有任何复制省略。在这些情况下,按值返回会产生一个副本,而按引用返回则不会。1.当t返回一个右值引用时,它的行为是否不同?返回右值引用的好理由是什么?我猜std::move可以,但它还有什么好处呢?
对于自由函数,通过右值引用返回没有什么意义。我能想到的唯一用例是当函数从参数接收对象并返回它或其中的某些内容时,并期望调用者从那里移动。对于一个成员函数,它可以是有用的,例如只是移动一个成员变量。See also。