Имеются ли переменные или нет?

17

Естественно, это не скомпилируется:

int &z = 3; // error: invalid initialization of non-const reference ....

, и это скомпилирует:

const int &z = 3; // OK

Теперь рассмотрим:

const int y = 3;
int && yrr = y; // const error (as you would expect)
int && yrr = move(y); // const error (as you would expect)

Но эти следующие строки компилируются для меня. Я думаю, что это не должно быть.

int && w = 3;
int && yrr = move(3);
void bar(int && x) {x = 10;}
bar(3);

Не будут ли эти две последние строки разрешать изменение буква 3? В чем разница между 3 и const int? И, наконец, есть ли опасность с «модификацией» литералов?

(g ++ - 4.6 (GCC) 4.6.2 с -std=gnu++0x -Wall -Wextra )

    
задан Aaron McDaid 22.12.2011 в 02:35
источник
  • Чтобы ответить на мой собственный вопрос: в move (3) возможно, что 3 копируется первым, чтобы создать временный int, будет уничтожен в конце инструкции. Это объяснение? –  Aaron McDaid 22.12.2011 в 02:37
  • В вашем втором утверждении: const & z = 3; вам не хватает спецификатора типа. поэтому он не компилируется. –  C Johnson 22.12.2011 в 02:38
  • Спасибо, @CJohnson, я обычно копирую и вставляю рабочий код здесь. Но я был невнимателен к этому лайнеру! –  Aaron McDaid 22.12.2011 в 02:39
  • Обратите внимание, что cv-квалификаторы действительно не применяются к неклассическим значениям. Вместо «const» термин «mutable» является более подходящим термином для использования. –  outis 22.12.2011 в 03:36

1 ответ

13

Ссылка rvalue на литерал 3 :

int && w = 3;

фактически привязан к временному, являющемуся результатом оценки выражения 3 . Это не связано с каким-то платоническим литералом 3.

(все ссылки на следующие стандарты приведены в проекте марта 2011 года, n3242)

3.10 / 1 "Lvalues ​​и rvalues"

  

Значение литерала, такого как 12, 7.3e5 или true, также является значением prvalue

Затем 8.5.3 «Ссылки» приводят правила о том, как привязка привязки попадает в последний случай, в котором говорится:

  

В противном случае временный тип «cv1 T1» создается и инициализируется из выражения инициализатора, используя правила для неосновной копии-инициализации (8.5). Ссылка затем привязана к временному.

и дает в качестве примера что-то очень близкое к тому, что в вашем вопросе:

double&& rrd = 2; // rrd refers to temporary with value 2.0
    
ответ дан Michael Burr 22.12.2011 в 02:45
  • Спасибо, но если это правда, то не должно ли это работать? move (3) = 6; Вместо этого я получаю ошибку "error: использование значения xvalue (rvalue reference) как lvalue". Пришло время для меня читать на xvalues ​​и prvalues, и все это снова :-) –  Aaron McDaid 22.12.2011 в 02:57
  • Благодаря вашему ответу, я думаю, что могу ответить на мой комментарий несколько секунд назад. Я вижу, что движение (3) является rvalue (очевидно, оно неназванное). Внутри моей функции void bar (int && x) {x = 10;} есть имя для x. Кажется, это разница между x = 6 и move (3) = 6. Оба являются &&, но одно - lvalue, а другое - нет. И это различие - это то, что приводит к сообщению об ошибке для перемещения (3) = 6. –  Aaron McDaid 22.12.2011 в 03:06
  • @Aaron: (Позднее) дополнение к вашему комментарию: где-то в стандарте указано, что имя rvalue является lvalue, так что да, именно так оно и работает. :) –  Xeo 11.01.2012 в 05:20