Каков наилучший способ вернуть строку в C ++?

Мой вопрос прост: если у меня есть некоторый класс Man, и я хочу определить функцию-член, которая возвращает имя человека, какой из следующих двух вариантов я предпочту?

Первый:

<code>string name();
</code>

Во-вторых:

<code>void name(/* OUT */ string &name);
</code>

Первый вариант является неэффективным, потому что он делает ненужные копии (локальная переменная -> возвращаемое значение -> переменная в левой части присваивания).

Второй вариант выглядит довольно эффектно, но заставляет плакать

<code>string name;
john.name(name);
</code>

вместо простого

<code>string name(john.name());
</code>

Итак, какой вариант я предпочитаю и каков правильный компромисс между эффективностью и удобством / удобочитаемостью?

Заранее спасибо.

 James Kanze11 мая 2012 г., 16:31
@ hmjd Извините, тогда. В шрифте, который я использую,:: не очень хорошо отображается.
 Christian Rau11 мая 2012 г., 16:30
Если это просто простой метод получения доступа к соответствующей переменной-члену, тоconst std::string& может быть, еще лучшая идея.
 hmjd11 мая 2012 г., 16:21
@ JamesKanze, это не часть подписи, а скорее мой комментарий, за ним следует ':'.
 hmjd11 мая 2012 г., 16:16
Примечание, какname() выглядит как запрос, чтобы сделать егоconst: string name() const;.
 James Kanze11 мая 2012 г., 16:19
@ hmjd Почему первыйconst? Возвращенный объект оказывается принадлежащим клиенту, и он должен иметь возможность делать с ним все, что хочет.

Ответы на вопрос(7)

тебе стоит использовать первый вариант. Потому что это простой метод получения и такой подход используется везд

,

вы можете использовать это:

string name();

Даже в C ++ 03 это почти хорошо, так как компилятор может оптимизировать это Поиск для оптимизации возвращаемого значения).

возможно, вам стоит пойти так:inline const std::string& name() const { return this->name; }

Так как имя возвращается как ссылка на константу, оно не будет изменено вне класса, также не будет создана копия при возврате имени.

После этого, если вы хотите манипулировать именем, вам нужно будет сделать копию.

 tonytony11 мая 2012 г., 16:50
Спасибо за ответ! Это имеет смысл, но я рассмотрел некоторую ситуацию, когда имя вычисляется внутри функции, например Функция 'fullname ()', которая возвращает фамилию и имя, соединенные вместе.
 Mesop11 мая 2012 г., 17:14
Да, в этом случае вам придется возвращать значение, так как ссылка на локальную переменную не будет действительной после возврата из функции. Альтернативой для вас может быть вычисление полного имени при каждом изменении имени или фамилии (вы можете сделать это вsetName илиsetFirstName методы) и сохраните его в поле полного имени. Таким образом, вам не придется пересчитывать полное имя каждый раз, когда вы звонитеfullname(), вам просто нужно вернуть константную ссылку на поле полного имени (как написано в моем ответе).
 tonytony11 мая 2012 г., 18:10
Да, ты прав =)

анят все издержки копирования.

Решение Вопроса

и тот факт, что вы его задаете, показывает, что вы обращаете внимание на свой код. Тем не менее, хорошая новость заключается в том, что в данном конкретном случае есть простой выход.

Первый, чистый метод - правильный способ сделать это. Компилятор удалит ненужные копии, в большинстве случаев (обычно там, где это имеет смысл).

EDIT (25.06.2016)

К сожалению, кажется, что сайт Дэвида Абарахама был отключен в течение нескольких лет, и эта статья была потеряна для эфира (копия archive.org недоступна). Я взял на себя смелость загрузить свою локальную копию в формате PDF для архивных целей, и это можно найти здесь.

 Mahmoud Al-Qudsi11 мая 2012 г., 16:19
Да, это очень хорошо написанное сообщение, которое действительно бьет по голове.
 Robᵩ11 мая 2012 г., 16:18
+ 1 за ссылку на отличную статью Дэйва Абрахамса.
 Mahmoud Al-Qudsi11 мая 2012 г., 16:45
Не за что. Удачи
 tonytony11 мая 2012 г., 16:44
Благодарность! Я прочитал статью и был Чрезвычайно сбит с толку, но это действительно убирает вещи. Теперь я должен очистить мой Эффективной code =)
 user60672311 мая 2012 г., 20:44
Конечно, я бы всегда использовал «второй вариант» для очень тяжелых переменных. Я чувствую, что этот метод может быть даже самокомментирующимся, потому что читатель предположит, что тип данных имеет большой вес. хотя бы мое мнение.

используйте первый вариант:

string name();

Компилятор, скорее всего, оптимизирует ненужные копии. Видеть оптимизация возвратной стоимости.

В C ++ 11 семантика перемещения означает, что вы не выполняете полную копию, даже если компилятор не выполняет RVO. Видеть переместить семантику.

Также имейте в виду, что если альтернатива

void name(std::string& s);

затем вы должны очень четко указать, что может произойти сs и какие значения он может иметь при передаче в функцию, и, вероятно, либо выполняет большую проверку достоверности, либо просто полностью перезаписывает ввод.

 Luchian Grigore11 мая 2012 г., 16:18
+ 1 Да, RVO делает это достаточно эффективным.

Мера, оптимизируй, измеряй. Или, как сказал Кнут, «преждевременная оптимизация - корень всего зла

Если у тебя нет явных признаков того, что просто возвращаешьсяstd::string существенно повлияет на производительность вашего программного обеспечения, просто сделайте это. Если ты можешь Мера значительное влияние, найти критический путь и оптимизироватьчт. Не делайте забавных «оптимизаций» для всего проекта, которые, скорее всего, приведут к небольшому или нулевому выигрышу в производительности, но отрицательно скажутся на удобочитаемости, удобстве обслуживания и надежности вашего код

Ваш ответ на вопрос