Почему я должен когда-либо возвращать что-то по значению, поскольку С++ содержит ссылки const?
Рассмотрим эту функцию:
Thing func(){
return something;
}
Каждый вызов этой функции, копия something
производится и передается вызывающему.
Мой вопрос: почему бы не просто сделать это (каждый раз, когда я хочу что-то вернуть по значению)?
const Thing& func(){
return something;
}
Таким образом, мы не рискуем копировать something
без повода для этого. Если клиенту нужно только "читать" из something
, но не "писать" ему, ссылка на const может сделать именно это. И если клиенту нужна копия, он может просто назначить ссылку на константу переменной, например:
Thing thing = func(); // the object is passed by const reference, and then copied.
Так есть ли когда-либо причина просто вернуться по значению?
Кстати, это не то, что меня так волнует оптимизация, просто я не вижу причины когда-либо возвращаться просто по значению.
Последующий вопрос: читая ответы, я понимаю, что для каждого метода есть плюсы и минусы. Есть ли по умолчанию? Например. msgstr "по умолчанию возврат по значению"? Или это чисто основано на конкретном случае?
Ответы
Ответ 1
Потому что, если ваш объект (по какой-либо причине) был создан в стек вызываемой функции, возвращение и использование ссылки на него - это поведение undefined.
С возвратом по значению компилятор иногда может оптимизировать возврат и нет опасных ссылок. С С++ 11 и перемещением семантики это выводится на новый уровень.
Не имеет смысла говорить "всегда лучше возвращаться по ссылке, а не по значению", каждый случай, когда он используется, должен рассматриваться отдельно.
Ответ 2
Так есть ли когда-либо причина просто вернуться по значению?
Да. Если вы возвращаете локальную переменную функции, например.
int compute(int a, int b)
{
int result;
// a lot of magic
return result;
}
Если эта функция должна была возвращать ссылку на result
любого типа, она была бы болтающейся.
Кроме того, возвращаемые функции локальные переменные с типом класса "по значению" могут быть оптимизированы с помощью копирования elision - имя оптимизации NRVO. И если эта оптимизация не применяется, новая введенная семантика перемещения может (хотя вы должны просто полагаться на copy elision, она работает очень хорошо). В таких случаях нет стимула возвращать ссылку.
Кроме того, вы не захотите возвращать ссылки, если хотите сохранить личные вещи. Зачем вам возвращать константную ссылку на переменную частного члена в публичной функции-члене? Он указывает, что существует переменная-член, информация, которую сайт вызова не должен знать.
Также обратите внимание на безопасность потоков. Возвращаемые переменные по ссылке могут привести к гонке данных, если один и тот же объект будет изменен другим потоком после return
-statement.
Или это чисто основано на конкретном случае?
В большинстве случаев вы возвращаетесь по значению, особенно для функций, не являющихся членами. Функции-члены могут возвращать ссылки на члены *, но вряд ли есть сценарии, в которых функция-не-член возвращает ссылки. Вы должны возвращать ссылки только тогда, когда знаете, что вам нужно (и что вы делаете).
* И также, только если им действительно нужно.
Ответ 3
Если вы возвращаете нестатистическую локальную переменную, то вы должны возвращаться по значению, так как она будет уничтожена, когда функция вернется, делая ссылки на нее недействительными. В этом случае копия часто может быть заменена движением или полностью исключена.
Если вы возвращаете что-то постоянное, тогда вы правы; обычно лучше вернуть ссылку и позволить вызывающему абоненту решить, следует ли ее копировать. Но могут быть и другие причины, такие как безопасность потоков, которые предпочитают возвращать значение даже тогда: возвращая копию, читатель не может получить доступ к постоянному объекту, а другой поток может его изменить.