Этот код не компилируется:
class C {};
void foo (C& c) {}
C bar() { return C(); }
int main()
{
foo(bar());
}
Ошибка компиляции (GCC 4.1.2) в строке foo(bar())
:
неверная инициализация неконстантной ссылки типа ‘C&’
из временного типа «С»
Как bar()
возвращает mutable
объект, он должен скомпилировать …
Почему C ++ не позволяет этот код выше?
РЕДАКТИРОВАТЬ: Я подвел итог в ответ ниже все хорошие идеи из всех ответов 😉
Здесь применимо правило, что вы не можете создать неконстантную ссылку на временный объект. Если foo
был объявлен как foo(const C&)
код будет в порядке.
Однако сам временный объект не является константой; вы можете вызывать неконстантные функции-члены, например, bar().non_const_member_function()
,
В C ++ 11 можно написать foo, чтобы получить ссылку на rvalue; в этом случае вызов будет в порядке:
void foo(C&&);
foo(bar()); // okay
Это потому, что значение, возвращаемое bar
это временный значение. Поскольку его существование является временным, вы не можете использовать указатель или ссылку на него.
Тем не менее, если вы храните копия из этого временного, как и во втором вашем изменении, вы больше не передаете ссылку на временный объект foo
, но ссылка на реальный материальный объект. И в первом случае, когда вы переходите к ссылке на константный объект, компилятор удостоверяется, что временный объект остается достаточно долго (согласно спецификации C ++).
Вопрос не с декларацией bar
но с этим из foo
, foo
принимает неconst
ссылка, и временные могут быть связаны только с const
ссылки (что затем продлевает время жизни временного объекта, чтобы соответствовать времени ссылки, с которым оно связано).
Разрешение неconst
Ссылка на временную привязку не имеет большого смысла. Неconst
ссылка подразумевает, что он будет изменять любой объект, связанный с ним. Модификация временного не имеет смысла, так как его срок службы ограничен, и изменения будут потеряны, как только он выйдет из области видимости.
Изменяемые (lvalue-) ссылки не привязываются к временным значениям. Тем не менее, const-ссылки делать привязка к временным значениям. Это не имеет никакого отношения к тому, является ли объект, возвращаемый значением, постоянным или нет; это просто вопрос того, является ли выражение временным или нет.
Например, следующее является действует:
struct C { void i_am_non_const() {} };
int main()
{
bar().i_am_non_const();
}
Это выбор дизайна. Здесь нет ничего невозможного. Просто выбор дизайна.
В C ++ 11 у вас есть третий вариант, который также превосходящий альтернатива:
void foo(C && c) {}
То есть используйте rvalue-ссылки.
Это не const, но это временно Rvalue. Как таковой, он не может связываться с неконстантным именующий ссылка.
Это может связать с const или Rvalue ссылка, и вы можете вызывать функции-члены (постоянные или нет) на нем:
class C { void f(); };
void foo_const(C const &);
void foo_rvalue(C &&);
foo_const( bar() ); // OK
foo_rvalue( bar() ); // OK
bar().f(); // OK
Настоящая, суровая правда заключается в том, что нет смысла ссылаться на временное значение.
Смысл передачи объекта по ссылке заключается в том, что он позволяет изменять его состояние. Однако в случае с временным по самой своей природе было бы не очень полезно иметь возможность изменять его, поскольку у вас нет способа получить другую ссылку на него позже в вашем коде, чтобы увидеть изменения.
Тем не менее, это несколько иначе, если у вас есть const
ссылка. Поскольку вы будете когда-либо читать только с const
ссылка, имеет смысл иметь возможность использовать временные там. Вот почему компилятор «взломает» его и предоставит более постоянный адрес временным файлам, в которые вы хотите «превратиться». const
Рекомендации.
Итак, правило таково, что вы не можете получитьconst
ссылка на временное значение. (Это немного изменилось в C ++ 11, где у нас есть новый тип ссылок, которые служат именно этой цели, но методы должны работать с ними особым образом.)
Спасибо всем за ваши ответы 🙂
Здесь я собираю ваши хорошие идеи 😉
Возврат по значению является не const
, Например, мы можем вызвать неконстантные функции-члены возврат по значению:
class C {
public:
int x;
void set (int n) { x = n; } // non-const function
};
C bar() { return C(); }
int main ()
{
bar.set(5); // OK
}
Но C ++ не допускает неконстантных ссылок на временные объекты.
Однако C ++ 11 допускает неконстантность RValue ссылки к временным объектам. 😉
class C {};
void foo (C& c) {}
C bar() { return C(); }
//bar() returns a temporary object
//temporary objects cannot be non-const referenced
int main()
{
//foo() wants a mutable reference (i.e. non-const)
foo( bar() ); // => compilation error
}
+ Изменить foo
декларация
void foo (const C& c) {}
Использовать другой объект
int main()
{
C c;
foo( c = bar() );
}
Используйте C ++ 11 Rvalue ссылка
void foo(C && c) {}
Чтобы подтвердить, что временные объекты являются константными, приведенный выше исходный код не работает по той же причине:
class C {};
void foo(C& c) {}
int main()
{
foo( C() );
}