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

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

Во-первых:

string name();

Во-вторых:

void name(/* OUT */ string &name);

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

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

string name;
john.name(name);

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

string name(john.name());

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

Спасибо заранее.

Ответ 1

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

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

EDIT (6/25/2016)

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

Ответ 2

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

string name();

Компилятор скорее всего оптимизирует любые ненужные копии. См. оптимизация возвращаемого значения.

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

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

void name(std::string& s);

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

Ответ 3

Поскольку вы хотите создать getter для поля вашего класса, возможно, вам стоит пойти так: inline const std::string& name() const { return this->name; }

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

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

Ответ 4

Я бы пошел первым. Оптимизация возвращаемого значения и С++ 11 удалят любые накладные расходы на копирование.

Ответ 5

Поскольку у нас есть перемещение-семантика (в С++ 11), вы можете использовать это:

string name();

Даже в С++ 03 это почти хорошо, так как компилятор может оптимизировать это (Search for Return Value Optimization).

Ответ 6

Правило №1 оптимизации: Измерение, оптимизация, измерение. Или, как сказал Кнут, "преждевременная оптимизация - это корень всего зла".

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

Ответ 7

Я думаю, вы должны использовать первый вариант. Поскольку это простой метод getter, и такой подход getter/setter используется везде.