C ++ 11: Почему разрешено присваивать значения? - PullRequest
5 голосов
/ 29 февраля 2012

Из того, что я понимаю, причина, по которой опасно возвращать rvalues-ссылки из функций, заключается в следующем коде:

T&& f(T&& x) { do_something_to_T(x); return static_cast<T&&>(x); }
T f(const T& x) { T x2 = x; do_something_to_T(x2); return x2; }
T&& y = f(T());

В результате y остается неопределенной висячей ссылкой.

Однако я не понимаю, почему приведенный выше код даже компилируется?Есть ли когда-либо законная причина присвоить ссылку на rvalue другой ссылке на rvalue?Разве r-значения не должны быть, грубо говоря, «временными», то есть станут недействительными в конце выражения?Возможность назначать их мне кажется глупой.

1 Ответ

9 голосов
/ 29 февраля 2012

Разве 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);

«Определенные операции», о которых я говорил, были «движущимися». Движение с объекта вполне возможно при двух условиях:

  1. Это все равно уйдет. IE: временный.
  2. Пользователь явно сказал, чтобы уйти от него.

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

Существует ровно две причины, по которым существуют ссылки на r-значение: для поддержки семантики перемещения и для поддержки идеальной пересылки (что требовало нового ссылочного типа, к которому они могли бы привязать механику приведения в стиле фанк, а также потенциально семантику перемещения). Поэтому, если вы не выполняете одну из этих двух операций, причины использования && сомнительны.

Действительно, я бы даже сказал, что параметры должны быть && только в двух случаях: функция пересылки или конструктор / присваивание перемещения. Во всех остальных случаях, если вы хотите разрешить перемещение, вы берете тип по значению , а не &&. Таким образом, вы заставляете перемещение происходить как часть вызова функции. Оттуда объект можно переместить в конечный пункт назначения.

...