Ссылочная инициализация в C++
Кто-нибудь может объяснить мне, почему есть разница между этими двумя утверждениями?
class A{};
const A& a = A(); // correct
A& b = A(); // wrong
Это говорит о недопустимой инициализации неконстантной ссылки типа A&
из временного типа A
Почему const
важно здесь?
5 ответов
Неконстантные ссылки должны быть инициализированы l-значениями. Если бы вы могли инициализировать их временными файлами, что бы вы сделали?
int& foo = 5;
foo = 6; // ?!
const
ссылки имеют особое свойство, что они продлевают жизнь рефери, и так как они const
, нет никакой возможности, что вы попытаетесь изменить то, что не хранится в памяти. Например:
const int& foo = 5;
foo = 6; // not allowed, because foo is const.
Помните, что ссылки на самом деле должны ссылаться на что-то, а не только на временные переменные. Например, действует следующее:
int foo = 5;
int& bar = foo;
bar = 6;
assert(foo == 6);
Терминология по этому вопросу немного сбивает с толку; Вы можете исследовать их немного дальше. Вот краткий ответ:
Вы назначаете временный объект (результат вызова конструктора класса) переменной. Временный объект - это R-значение. Вы не можете присвоить R-значение неконстантной ссылке.
Вам разрешено присваивать R-значение константной ссылке, хотя обоснование его разрешения довольно неясно.
В языке C++ запрещается прикреплять неконстантную ссылку к rvalue, в то время как совершенно нормально прикреплять константную ссылку к rvalue. Например, это законно
const int& r = 5;
пока это не
int &r = 5; // ERROR
Временный объект типа A
возвращается выражением A()
является значением r, поэтому приведенное выше правило применимо и в вашем случае.
Для временного /rvalue вы можете иметь только константную ссылку.
Вы можете иметь неконстантную ссылку на не временную /lvalue.
A a;
A& b = a;
Я полагаю, что причина состоит в том, чтобы усилить тот факт, что значение является временным, поскольку нет никакой ценности в возможности изменить то, что собирается на мгновение исчезнуть.
Потому что стандарт говорит так:
§8.5.3.5... В противном случае ссылка должна быть ссылкой lvalue на энергонезависимый тип const...
Однако, если вы хотите этого очень сильно, вы можете получить это:
#include <iostream>
int main()
{
const int & cr=5;
int & r=const_cast<int &>(cr);
r=6;
std::cout<<r;
}
// outputs 6 with c++/clang++, Debian 8, amd64
Но имейте в виду, что предполагаемая константа cr больше не является константой, и вы подвергаетесь неопределенному поведению. (§1.9 (4))
Как следует из приведенного выше кода, нет технической причины для различия. Скорее, у дизайнеров были кошмары о том, что пользователи будут делать с неконстантными ссылками на временные ссылки.