Ответ 1
Функция никогда не должна возвращать ссылку на локальный объект/переменную, поскольку такие объекты выходят из области видимости и уничтожаются при возврате из функции.
Иными словами, функция может возвращать постоянную или неконстантную ссылку на объект, область действия которого не ограничена контекстом функции. Типичным примером является пользовательский operator<<
:
std::ostream & operator<<(std::ostream &out, const object &obj)
{
out << obj.data();
return out;
}
К сожалению, возврат по значению имеет свой недостаток производительности. Как упоминал Крис, возвращение объекта по значению включает в себя копию временного объекта и его последующее уничтожение. Копирование выполняется с помощью либо конструктора копирования, либо operator=
. Чтобы избежать этой неэффективности, умные компиляторы могут применять оптимизации RVO или NRVO, но в некоторых случаях они не могут - многократные возвраты.
В готовящемся стандарте С++ 0x, частично доступном в gnu gcc-4.3, вводится ссылка на rvalue [& & amp;], которая может использоваться для различения lvalue от ссылки на rvalue. Благодаря этому можно реализовать конструктор перемещения, полезный для возврата объекта, частично избегая затрат на конструктор копирования и деструктор временного объекта.
Конструктор перемещения - это то, что Андрей задумал несколько лет назад в статье http://www.ddj.com/database/184403855, предложенной Крисом.
Конструктор перемещения имеет следующую подпись:
// move constructor
object(object && obj)
{}
и предполагается, что он переходит во владение внутренними объектами переданного объекта, оставляя последний в состоянии по умолчанию. Благодаря этому можно избежать копий внутренних органов и упростить уничтожение временных. Типичная фабрика функций будет иметь следующую форму:
object factory()
{
object obj;
return std::move(obj);
}
std::move()
возвращает ссылку на значение из объекта. И последнее, но не менее важное, конструкторы перемещения позволяют возвращать ссылку на неопределяемые объекты.