Std:: перемещение по переменной, которая уже есть T &&

На странице Как создать конструктор Move Move В Microsoft есть пример того, как написать конструктор перемещения. По существу это форма:

MyClass::MyClass(MyClass&& lhs)
{
    *this = std::move(lhs);
}

Я пробовал, и std::move действительно требуется здесь, но почему? Я думал, что единственным движением было преобразование в T&&. Но lhs уже имеет тип MyClass&&, не так ли?

Ответ 1

Именованные ссылки rvalue - lvalues. Без названия ссылки rvalues ​​являются значениями. Это важно понять, почему вызов std:: move необходим в: foo&& r = foo(); foo f = std::move(r);

Взгляните на этот ответ: fooobar.com/info/2138/... Это очень хорошо объясняет.


Взгляните на эту функцию:

void foo(X&& x)
{
  X anotherX = x;
  // ...
}

Интересный вопрос: какая перегрузка конструктора X copy вызывается в теле foo? Здесь X - это переменная, объявленная как ссылка rvalue. Поэтому вполне правдоподобно ожидать, что сам X должен также связываться как rvalue, т.е. X(X&& rhs); следует вызвать.

Разрешающая семантика перемещения применяется молчаливо к тому, что имеет имя, как в

X anotherX = x;
// x is still in scope!

будет опасно запутанным и подверженным ошибкам, потому что вещь, из которой мы только что переехали, то есть вещь, которую мы только что похитили, по-прежнему доступна на последующих строках кода. Но вся суть семантики перемещения заключалась в том, чтобы применять ее только там, где она "не имеет значения", в том смысле, что вещь, с которой мы двигаемся, умирает и уходит сразу после перемещения.

Вот почему дизайнеры ссылок rvalue выбрали решение, немного более тонкое, чем это:

Вещи, объявленные как ссылка rvalue, могут быть lvalues ​​или rvalues. Отличительный критерий: если он имеет имя, то это значение lvalue. В противном случае это значение r.

Источник: http://thbecker.net/articles/rvalue_references/section_05.html