Временные объекты не могут быть привязаны к непостоянным ссылкам. int (12) в этом случае является временным.
Prasoon Saurav
@PrasoonSaurav Что вы имеете в виду под временными 12? Отсутствие концепций здесь (с моей стороны :))
Aquarius_Girl
2
Обратите внимание, что для этого ограничения нет строгой технической причины. Так же легко было бы реализовать возможность изменения ссылок на временные библиотеки. Запрещение этого - проектное решение C ++, так как такая конструкция была бы плохой конструкцией с гораздо большим риском непреднамеренного злоупотребления, чем подлинная полезность. (Я только однажды обнаружил надуманную потребность в такой вещи.)
Керрек С.Б.
@KerrekSB - самая распространенная потребность в привязке ref к объекту rvalue(ostringstream() << "x=" << x).str()
любопытный парень
@curiousguy: Да, это содержание опубликованной мной ссылки.
Kerrek SB
Ответы:
132
В C ++ 03 3.10 / 1 сказано: «Каждое выражение является либо lvalue, либо rvalue». Важно помнить, что ценность по сравнению с ценностью - это свойство выражений, а не объектов.
Lvalues именуют объекты, которые сохраняются за пределами одного выражения. Так , например, obj, *ptr, ptr[index]и ++xвсе lvalues.
Rvalue - это временные значения, которые испаряются в конце полного выражения, в котором они живут («точка с запятой»). Так , например, 1729, x + y, std::string("meow")и x++все rvalues.
Оператор адреса требует, чтобы его «операнд был lvalue». если бы мы могли взять адрес одного выражения, это выражение было бы lvalue, иначе это rvalue.
« если бы мы могли взять адрес одного выражения, выражение было бы lvalue, иначе - rvalue». Если бы только C ++ был таким простым! (но нюанс здесь не очень актуален) "R-значения временные" какие временные? объекты?
curiousguy
2
@curiousguyRvalues - это временные значения, которые исчезают в конце полного выражения, в котором они живут. Чтобы просто ответить, почему выражение int & = 12;недействительно, стандарт говорит, что строковый литерал является lvalue, другие литералы - rvalue.
BruceAdi
@curiousguy: Да. Rvalues являются временными объектами , но не все rvalue являются временными объектами; некоторые даже не объекты.
Nawaz
« Например, 1729, x + y, std :: string (« мяу ») и x ++ - все rvalue. » Но std::string("meow")конструирует объект типа std::stringи выдает rvalue, которое обозначает этот объект, 1729не имеет побочных эффектов и дает значение 1729 как значение типа int.
curiousguy
1
@curiousguy: Это "Lvalues name objects that persist beyond a single expression."на 100% правильное утверждение. Напротив, ваш пример (const int &)1неверен, потому что это НЕ «именованный» объект.
Nawaz
53
int &z = 12;
С правой стороны временный объект типа intсоздается из интегрального литерала 12, но временный объект не может быть привязан к неконстантной ссылке. Отсюда и ошибка. Это то же самое, что:
int &z = int(12); //still same error
Почему создается временное? Поскольку ссылка должна ссылаться на объект в памяти, и для того, чтобы объект существовал, он должен быть сначала создан. Поскольку объект не имеет имени, это временный объект. У него нет названия. Из этого объяснения стало довольно ясно, почему второй случай хорош.
Временный объект может быть привязан к ссылке const, что означает, что вы можете сделать это:
constint &z = 12; //ok
Справочник по C ++ 11 и Rvalue:
Для полноты картины я хотел бы добавить, что в C ++ 11 введена ссылка на rvalue, которая может связываться с временным объектом. Итак, в C ++ 11 вы можете написать это:
int && z = 12; //C+11 only
Обратите внимание, что есть &&intead of &. Также обратите внимание, что constэто больше не нужно, даже если объект, с которым zсвязывается, является временным объектом, созданным из интегрального литерала 12.
Поскольку в C ++ 11 введена ссылка на rvalue , int&отныне она называется lvalue-reference .
@curiousguy, будьте последовательны, вы сказали: «Вы должны понимать, что это правила C ++. Они существуют и не нуждаются в обосновании» (не говоря уже о первом издании). Как мне интерпретировать ваши жалобы на то, что вы не отдаете то, что, по вашему мнению, не нужно?
Михаил Крелин - хакер
2
@ MichaelKrelin-hacker: Технически нет, вы не можете (никогда) привязать ссылку к значению (или постоянной времени компиляции), стандарт довольно четко описывает, что на самом деле происходит: в противном случае создается временный объект типа «cv1 T1» и инициализируется из выражения инициализатора с использованием правил для инициализации не ссылочной копии (8.5). Затем ссылка привязывается к временному. То есть синтаксис разрешен, но семантика не связана с привязкой ссылки к константе, а скорее с привязкой ее к временному, которое неявно создается.
Дэвид Родригес - dribeas
1
@curiousguy: Правила языка являются частью дизайна, и чаще всего есть обоснования того, почему язык был разработан таким образом. В этом конкретном случае, как и в C, вам не разрешено брать адрес значения (у него его нет), и вы не можете привязать ссылку. Теперь рассмотрим функцию void f( vector<int> const & ), которая идиоматична для передачи вектора, который не должен быть изменен. Теперь проблема в том, что это f( vector<int>(5) )было бы неправильно, и пользователю пришлось бы предоставить другую перегрузку, void f( vector<int> v ) { f(v); }которая является тривиальной.
Дэвид Родригес - дрибэас
1
... теперь, поскольку это было бы болезненно для пользователей языка, дизайнеры решили, что компилятор выполнит эквивалентную операцию для вас, в вызове f( vector<int>(5) )компилятор создает временный, а затем связывает ссылку с этим временным, и аналогично если было неявное преобразование из 5напрямую. Это позволяет компилятору генерировать единую подпись для функции и позволяет реализовать функцию одним пользователем. С этого момента аналогичное поведение определяется для остальных случаев использования постоянных ссылок для согласованности.
Дэвид Родригес - dribeas
1
@ MichaelKrelin-hacker: ссылки - это псевдонимы объектов, а значение - не объект. В зависимости от контекста ссылки могут быть просто псевдонимом, компилятор удаляет ссылку и просто использует идентификатор для обозначения того, что имел в виду исходный объект ( T const & r = *ptr;любое последующее использование rв функции может быть заменено на *ptr, и rне обязательно должно существовать во время выполнения) или его, возможно, придется реализовать, сохранив адрес объекта, которому он присваивает псевдоним (рассмотрите возможность сохранения ссылки как члена объекта) - что реализовано как указатель с автоматическим разыменованием.
Дэвид Родригес - dribeas
4
Привязка неконстантных и константных ссылок подчиняется разным правилам
Это правила языка C ++:
выражение, состоящее из буквального числа ( 12), является "rvalue"
не разрешено создавать неконстантную ссылку с rvalue: неправильно int &ri = 12;сформировано
разрешено создавать константную ссылку с rvalue: в этом случае неименованный объект создается компилятором; этот объект будет существовать, пока существует сама ссылка.
Вы должны понимать, что это правила C ++. Они просто есть.
Легко изобрести другой язык, скажем C ++ ', с немного другими правилами. В C ++ 'было бы разрешено создать неконстантную ссылку с rvalue. Здесь нет ничего непоследовательного или невозможного.
Но это позволило бы получить некоторый рискованный код, в котором программист мог бы не получить то, что он задумал, и разработчики C ++ справедливо решили избежать этого риска.
Ссылки - это «скрытые указатели» (ненулевые) на вещи, которые могут изменяться (lvalues). Вы не можете определить их как константу. Это должна быть «переменная» вещь.
РЕДАКТИРОВАТЬ::
Я думаю о
int &x = y;
как почти эквивалент
int* __px = &y;
#define x (*__px)
где __px- новое имя, и #define xработает только внутри блока, содержащего объявление xссылки.
Да, я имел в виду вашу формулировку «ссылки - это указатели на вещи, которые могут измениться» - речь идет о бесплатных ссылках.
Михаил Крелин - хакер
« Ссылки - это« скрытые указатели » « неправильные » вещи, которые могут изменить « неправильные » вещи, которые могут измениться (lvalues). « Неправильно »
(ostringstream() << "x=" << x).str()
Ответы:
В C ++ 03 3.10 / 1 сказано: «Каждое выражение является либо lvalue, либо rvalue». Важно помнить, что ценность по сравнению с ценностью - это свойство выражений, а не объектов.
Lvalues именуют объекты, которые сохраняются за пределами одного выражения. Так , например,
obj
,*ptr
,ptr[index]
и++x
все lvalues.Rvalue - это временные значения, которые испаряются в конце полного выражения, в котором они живут («точка с запятой»). Так , например,
1729
,x + y
,std::string("meow")
иx++
все rvalues.Оператор адреса требует, чтобы его «операнд был lvalue». если бы мы могли взять адрес одного выражения, это выражение было бы lvalue, иначе это rvalue.
&obj; // valid &12; //invalid
источник
int & = 12;
недействительно, стандарт говорит, что строковый литерал является lvalue, другие литералы - rvalue.std::string("meow")
конструирует объект типаstd::string
и выдает rvalue, которое обозначает этот объект,1729
не имеет побочных эффектов и дает значение 1729 как значение типаint
."Lvalues name objects that persist beyond a single expression."
на 100% правильное утверждение. Напротив, ваш пример(const int &)1
неверен, потому что это НЕ «именованный» объект.int &z = 12;
С правой стороны временный объект типа
int
создается из интегрального литерала12
, но временный объект не может быть привязан к неконстантной ссылке. Отсюда и ошибка. Это то же самое, что:int &z = int(12); //still same error
Почему создается временное? Поскольку ссылка должна ссылаться на объект в памяти, и для того, чтобы объект существовал, он должен быть сначала создан. Поскольку объект не имеет имени, это временный объект. У него нет названия. Из этого объяснения стало довольно ясно, почему второй случай хорош.
Временный объект может быть привязан к ссылке const, что означает, что вы можете сделать это:
const int &z = 12; //ok
Справочник по C ++ 11 и Rvalue:
Для полноты картины я хотел бы добавить, что в C ++ 11 введена ссылка на rvalue, которая может связываться с временным объектом. Итак, в C ++ 11 вы можете написать это:
int && z = 12; //C+11 only
Обратите внимание, что есть
&&
intead of&
. Также обратите внимание, чтоconst
это больше не нужно, даже если объект, с которымz
связывается, является временным объектом, созданным из интегрального литерала12
.Поскольку в C ++ 11 введена ссылка на rvalue ,
int&
отныне она называется lvalue-reference .источник
12
- это константа времени компиляции, которую нельзя изменить в отличие от данных, на которые ссылаетсяint&
. Что вы можете сделать, этоconst int& z = 12;
источник
void f( vector<int> const & )
, которая идиоматична для передачи вектора, который не должен быть изменен. Теперь проблема в том, что этоf( vector<int>(5) )
было бы неправильно, и пользователю пришлось бы предоставить другую перегрузку,void f( vector<int> v ) { f(v); }
которая является тривиальной.f( vector<int>(5) )
компилятор создает временный, а затем связывает ссылку с этим временным, и аналогично если было неявное преобразование из5
напрямую. Это позволяет компилятору генерировать единую подпись для функции и позволяет реализовать функцию одним пользователем. С этого момента аналогичное поведение определяется для остальных случаев использования постоянных ссылок для согласованности.T const & r = *ptr;
любое последующее использованиеr
в функции может быть заменено на*ptr
, иr
не обязательно должно существовать во время выполнения) или его, возможно, придется реализовать, сохранив адрес объекта, которому он присваивает псевдоним (рассмотрите возможность сохранения ссылки как члена объекта) - что реализовано как указатель с автоматическим разыменованием.Привязка неконстантных и константных ссылок подчиняется разным правилам
Это правила языка C ++:
12
), является "rvalue"int &ri = 12;
сформированоВы должны понимать, что это правила C ++. Они просто есть.
Легко изобрести другой язык, скажем C ++ ', с немного другими правилами. В C ++ 'было бы разрешено создать неконстантную ссылку с rvalue. Здесь нет ничего непоследовательного или невозможного.
Но это позволило бы получить некоторый рискованный код, в котором программист мог бы не получить то, что он задумал, и разработчики C ++ справедливо решили избежать этого риска.
источник
Ссылки - это «скрытые указатели» (ненулевые) на вещи, которые могут изменяться (lvalues). Вы не можете определить их как константу. Это должна быть «переменная» вещь.
РЕДАКТИРОВАТЬ::
Я думаю о
int &x = y;
как почти эквивалент
int* __px = &y; #define x (*__px)
где
__px
- новое имя, и#define x
работает только внутри блока, содержащего объявлениеx
ссылки.источник
const
:)const