Разве r-значения не являются, грубо говоря, «временными», то есть станут недействительными в конце выражения?
Нет, это не так.
Учитывая вашу функцию f
, это так же законно:
T t{};
T&& y = f(std::move(t));
Это совершенно правильный код C ++ 11. И это также четко определило, что происходит.
Единственная причина, по которой ваш код не определен, заключается в том, что вы передаете временный. Но ссылки на r-значения не обязательно должны быть временными.
Для уточнения, ссылка r-значения концептуально является ссылкой на значение, из которого определенные операции считаются допустимыми для выполнения, что в противном случае было бы неприемлемым для выполнения.
Ссылки на R-значения очень тщательно определены в C ++ 11. Ссылка на l-значение может быть привязана к любому временному объекту без необходимости приведения или чего-либо еще:
T t{};
T &y = t;
Ссылка на r-значение может быть только неявно привязанной к временному или другому «xvalue» (объекту, который наверняка исчезнет в ближайшем будущем):
T &&x = T{};
T &&no = t; //Fail.
Чтобы связать ссылку на r-значение с ненулевым значением, вам нужно выполнить явное приведение. То, как C ++ 11 использует заклинание, говорит: std::move
:
T &&yes = std::move(t);
«Определенные операции», о которых я говорил, были «движущимися». Движение с объекта вполне возможно при двух условиях:
- Это все равно уйдет. IE: временный.
- Пользователь явно сказал, чтобы уйти от него.
И это только два случая, когда ссылка на r-значение может связываться с чем-либо.
Существует ровно две причины, по которым существуют ссылки на r-значение: для поддержки семантики перемещения и для поддержки идеальной пересылки (что требовало нового ссылочного типа, к которому они могли бы привязать механику приведения в стиле фанк, а также потенциально семантику перемещения). Поэтому, если вы не выполняете одну из этих двух операций, причины использования &&
сомнительны.
Действительно, я бы даже сказал, что параметры должны быть &&
только в двух случаях: функция пересылки или конструктор / присваивание перемещения. Во всех остальных случаях, если вы хотите разрешить перемещение, вы берете тип по значению , а не &&
. Таким образом, вы заставляете перемещение происходить как часть вызова функции. Оттуда объект можно переместить в конечный пункт назначения.