简体   繁体   English

为什么我必须在右值引用上调用 move ?

[英]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.

相关问题 为什么我们需要在移动构造函数中将右值引用设置为 null? - Why do we need to set rvalue reference to null in move constructor? 我应该如何确保对move构造函数的调用? (移动语义和右值参考) - How should I ensure the call to the move constructor? (move semantics and rvalue reference) 为什么移动返回一个rvalue引用参数需要用std :: move()包装它? - Why move return an rvalue reference parameter need to wrap it with std::move()? 将参考(右值)移至功能 - Move reference (rvalue) to function 为什么除了在 Uref 实施例中对右值的引用之外,还允许 std::move 接受对右值的引用? - Why was it nessesury to allow std::move accept reference to rvalue besides reference to rvalue in Uref embodiment for both? 为什么我可以为右值引用赋值? - Why can i assign a value to a rvalue reference? 为什么移动构造函数需要使用“右值引用”? - Why does a move constructor need to use “rvalue reference”? 为什么需要在move构造函数中将右值引用设置为null? - Why need to set rvalue reference to null in move constructor? std :: move into static_pointer_cast:为什么static_pointer_cast没有rvalue引用重载? - std::move into static_pointer_cast: Why doesn't static_pointer_cast have an rvalue reference overload? 为什么std :: move将rvalue引用作为参数? - Why does std::move take rvalue reference as argument?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM