C ++ ссылки против возвращаемых значений - PullRequest
6 голосов
/ 12 декабря 2010

Я понимаю, что основной принцип ссылок - избегать создания копий больших структур, но что если сама функция, которую вы пишете, создает большую структуру? Является ли менее эффективным (или более вероятно, что вам не хватит памяти) создать переменную локально, а затем вернуть ее, чем передавать объект назначения в качестве ссылки и заполнить его из функции?

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

void getLines(std::string in, std::vector<std::string>& out);

над

std::vector<std::string> getLines(std::string in);

Спасибо за любую помощь, Wyatt

Ответы [ 4 ]

5 голосов
/ 12 декабря 2010

Первый пример, вероятно, должен быть похож на один из следующих:

void getLines(std::string in, std::vector<std::string> &out);
void getLines(std::string in, std::vector<std::string> *out);

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

http://en.wikipedia.org/wiki/Return_value_optimization

То, будет ли это видно на практике, зависит от компилятора, уровней оптимизации и от того, сможет ли компилятор определить эту возможность в первую очередь.

Хотя я говорю не за всех, мне никогда не удавалось заставить компиляторы использовать преимущества RVO, даже с простыми объектами, которые не делают ничего фантастического. Поэтому я лично рекомендую первый подход, потому что вы гарантированно получите желаемое поведение на каждом компиляторе и (что кажется мне актуальным ...) для кода каждого программиста - то есть, что объект, созданный для хранения возврата значение заполняется непосредственно вызываемой функцией без каких-либо дополнительных копий.

(Стоимость создания объекта результата по умолчанию, которого потенциально можно было бы избежать, если использовать RVO, обычно незначительна по сравнению с копией, которую компилятор мог бы избежать.)

Еще один момент, на который следует обратить внимание: если вы пытаетесь избежать ненужных копий, передача объектов по константной ссылке, а не по значению часто является хорошей идеей, например ::

void getLines(const std::string &in, std::vector<std::string> &out);
void getLines(const std::string &in, std::vector<std::string> *out);
5 голосов
/ 12 декабря 2010

Это зависит от того, поддерживает ли ваш компилятор оптимизация возвращаемого значения (большинство так и делают) и от того, соответствует ли код этой оптимизации.

1 голос
/ 25 октября 2013

Я советую написать код так, чтобы использование клиента было как можно более интуитивно понятным.

Если - как это обычно бывает - вы считаете, что возврат осуществляется по значению, тогда, если ваша система обладает производительностьюкритический, и вы обнаружите, что конкретное возвращаемое значение не оптимизируется приятным образом вашим компилятором - даже при самом высоком разумном уровне оптимизации , который вы можете использовать и после проверки любых соответствующих параметров командной строки или подсказок компилятора по достижению RVO, ирассматривая альтернативные компиляторы, если это целесообразно - в идеале C ++ 11 компилятор, который выигрывает от всегда эффективной семантики перемещения , только затем измените конкретное проблемное место, чтобы принять возвращаемое значение по ссылке.

1 голос
/ 12 декабря 2010

Ну, в вашем конкретном случае (заполнение контейнера значениями) я бы выбрал подход итератора ввода.Но во всех других случаях (например, сложное генерирование строк или некоторые вычисления) я не буду заботиться о возможных падениях производительности и доверять RVO (см. Ответ Джима) и компилятору, чтобы оптимизировать его так, как он должен.Если это становится узким местом (профиль!), Измените это конечно!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...