[英]Why do I have to call move on an rvalue reference?
In the code below, why doesn't the first call mkme = mvme_rv
dispatch to T& operator=(const T&&)
?在下面的代码中,为什么不首先调用
mkme = mvme_rv
分派给T& operator=(const T&&)
?
#include <iostream>
#include <string>
#include <vector>
using namespace std;
using T = vector<int>;
int main()
{
T mvme(10, 1), mkme;
T&& mvme_rv = move(mvme); // rvalue ref?
mkme = mvme_rv; // calls T& operator=(const T&)?
cout << mvme.empty(); // 0
mkme = move(mvme_rv); // calls T& operator=(const T&&)?
cout << mvme.empty(); // 1
}
As skypjack correctly comments, accessing an object through its name always results in an lvalue reference.正如 skypjack 正确评论的那样,通过名称访问对象总是会导致左值引用。
This is a safety feature and if you think it through you will realise that you are glad of it.这是一项安全功能,如果您仔细考虑,您会发现您对此很高兴。
As you know, std::move
simply casts an l-value reference to an r-value reference.如您所知,
std::move
只是将左值引用转换为右值引用。 If we use the returned r-value reference immediately (ie un-named) then it remains an r-value reference.如果我们立即使用返回的 r 值引用(即未命名),那么它仍然是一个 r 值引用。
This means that the use of the r-value can only be at the point in the code where move(x)
is mentioned.这意味着 r 值的使用只能在代码中提到
move(x)
地方。 From a code-reader's perspective, it's now easy to see where x's state became undefined.从代码阅读者的角度来看,现在很容易看出 x 的状态在哪里变得未定义。
so:所以:
1: auto x = make_x();
2: auto&& r = std::move(x);
3: // lots of other stuff
35: // ...
54: // ...
55: take_my_x(r);
does not work.不起作用。 If it did, someone maintaining the code would have a hard time seeing (and remembering) that x (defined on line 1) enters an undefined state on line 55 through a reference taken on line 2.
如果是这样,那么维护代码的人将很难看到(并记住)x(在第 1 行定义)通过第 2 行的引用在第 55 行进入未定义状态。
This is a good deal more explicit:这是一个更明确的交易:
1: auto x = make_x();
2: //
3: // lots of other stuff
35: // ...
54: // ...
55: take_my_x(std::move(x));
This line of code:这行代码:
mkme = mvme_rv;
is a copy and will thus use a copy assignment ( T& operator=(const T&)
).是一个副本,因此将使用副本分配(
T& operator=(const T&)
)。 The key thing about this is BOTH objects can be used afterwards and should - if implemented correctly - provide two identical objects.关键是这两个对象都可以在之后使用,并且应该 - 如果正确实现 - 提供两个相同的对象。
By contrast, this line of code:相比之下,这行代码:
mkme = move(mvme_rv);
is a move assignment ( T& operator=(const T&&)
).是移动分配(
T& operator=(const T&&)
)。 By convention, this will trash the mvme_rv
object (or at least clear it) and make mkme
basically what mvme_rv
was previously.按照惯例,这将
mvme_rv
对象(或至少清除它)并使mkme
基本上与mvme_rv
以前相同。
Effectively T&&
means a temporary object (aka xvalue) - something that will not last.有效地
T&&
意味着一个临时对象(又名 xvalue) - 不会持久的东西。 The std::move
method basically casts the object to a temporary (credit to @richard-Hodges for that wording). std::move
方法基本上将对象转换为临时对象(归功于@richard-Hodges 的措辞)。 This can then be used in the move assignment method.然后可以在移动分配方法中使用它。
So finally to answer you question of why doesn't mkme = mvme_rv
dispatch to T& operator=(const T&&)
: it's because mvme_rv
isn't a temporary object (aka xavalue).所以最后回答你为什么不
mkme = mvme_rv
分派给T& operator=(const T&&)
:这是因为mvme_rv
不是临时对象(又名 xavalue)。
More about xvalues: http://en.cppreference.com/w/cpp/language/value_category有关 xvalues 的更多信息: http ://en.cppreference.com/w/cpp/language/value_category
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.