Почему объекты 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, когда вы на самом деле нет - семантика кода может/будет неправильной и будет багги. есть и другие причины привязан к адресам, литералам и т. д. Это было перед переездом и семантика ее затвердела, и есть некоторая мотивация к движению и ее семантика.