Почему объекты c++ lvalue не могут быть привязаны к ссылкам rvalue (&&)?

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

Почему C++ не позволяет привязывать объекты lvalue к ссылкам rvalue? Оба позволяют мне изменить ссылочный объект, таким образом, для меня нет никакой разницы с точки зрения доступа к внутренним объектам ссылки.

единственная причина, по которой я могу догадаться, - это проблемы с перегрузкой неоднозначности.

2 ответов


но почему C++ не позволяет привязывать объекты lvalue к ссылкам rvalue?

предполагая, что вы имеете в виду "почему C++ не позволяет привязывать ссылки rvalue к объектам lvalue" - это так. Это просто не автоматически, поэтому вы должны использовать std::move чтобы сделать его явным.

почему? Потому что в противном случае безобидный вызов функции может неожиданно уничтожить то, чего вы не ожидали кому:

Class object(much,state,many,members,wow);
looks_safe_to_me(object);
// oh no, it destructively copied my object!

и

Class object(much,state,many,members,wow);
obviously_destructive(std::move(object));
// same result, but now the destruction is explicit and expected

заметка о разрушительном копировании: почему я говорю диструктивные и уничтожение выше я не имею в виду, что деструктор объекта заканчивает свое время жизни: просто его внутреннее состояние было перемещено в новый экземпляр. Это все еще действительный объект, но больше не имеет того же дорогостоящего состояния, что и раньше.


примечание по терминологии: давайте посмотрим, можем ли мы прояснить неточное использование lvalue, правосторонним значением etc. выше.

цитирую cppreference для потомков:

  • an lvalue is

    выражение и удостоверение и невозможно переместить из.

    таким образом, нет такой вещи, как объект lvalue, но есть объект, который локально назван (или упоминается) lvalue выражение

  • an правосторонним значением is

    выражение, которое является либо prvalue или xvalue. Это можно переместить из. Он может иметь или не иметь идентичности.

    • a prvalue (pure rvalue)-это примерно выражение, относящееся к безымянному временному объекту: мы не можем преобразовать наше выражение lvalue в один из этих IIUC.

    • an xvalue (истекающий значение)

      выражение и удостоверение и можно переместить из.

      , которая явно включает в себя результат std::move

так что же на самом деле происходит:

  • объект существует
  • объект идентифицируется локально выражением lvalue, которое нельзя переместить из (Чтобы защитить нас от неожиданные побочные эффекты)
  • std::move дает выражение xvalue (которое можно переместить), относящееся к тому же объекту, что и выражение lvalue
  • это означает, что такие объекты, как переменные (которые называются выражениями lvalue), не могут быть имплицитно переехал, а должен вместо явно перемещено из через явное выражение xvalue, такое как std::move.
  • анонимные временные, вероятно, уже упоминаются выражения prvalue и могут быть перемещены неявно

По сути, необходим механизм для различения значений, из которых можно перемещать, и тех, из которых нельзя перемещать (т. е. потребуется копия).

разрешение привязки rvalues и lvalues к ссылке lvalue делает это невозможным.

следовательно, значения, привязанные к ссылке rvalue, могут быть перемещены (не обязательно всегда будут перемещены, но это разрешено), а lvalues могут быть привязаны к ссылкам lvalue и не могут быть перемещены от.

std::move есть ли возможность для приведения между категориями значений (к rvalue), чтобы разрешить перемещение.

Примечание; const lvalue ссылки (const T&) может быть привязан как к rvalues (temporaries), так и к lvalues, поскольку упомянутый объект не может измениться (он помечен как const таким образом, в любом случае не может быть никакого движения).

существует некоторая история (назад к ранним дням c++), почему временные объекты не могут быть привязаны к non-const lvalue начнем с ссылок... деталь размыта, но это было какое-то рассуждение, что изменение временного не имеет смысла, так как он все равно разрушится в конце текущего оператора. Кроме того, вы можете быть убаюканы в том смысле, что вы изменяете lvalue, когда вы на самом деле нет - семантика кода может/будет неправильной и будет багги. есть и другие причины привязан к адресам, литералам и т. д. Это было перед переездом и семантика ее затвердела, и есть некоторая мотивация к движению и ее семантика.