В С++ существует ли преимущество эффективности при передаче примитивных типов по ссылке вместо возврата по значению?
Любая эффективность помогает передавать примитивные типы по ссылке вместо возврата по значению?
Ответ 1
[...] есть ли эффективность для передачи примитивных типов по ссылке вместо возврата по значению?
Вряд ли. Прежде всего, если у вас нет данных из вашего профилировщика, которые дают вам основания для этого, вам не следует беспокоиться о проблемах с производительностью при разработке вашей программы. Выберите простейший дизайн и дизайн, который наилучшим образом связывает ваше намерение.
Более того, примитивные типы обычно дешевы для копирования, поэтому это вряд ли будет узким местом в вашем приложении. И поскольку это самый простой вариант, и тот, который делает интерфейс функции более ясным, , вы должны пройти по значению.
Просто глядя на подпись, ясно, что функция, такая как:
void foo(int);
Не будет храниться ссылка на аргумент (и, следовательно, не будет возникать в таких проблемах, как оборванные ссылки или указатели), не будет изменять аргумент способом, который является видимым для вызывающего, и так далее и т.д..
Ничего из вышеизложенного не может быть выведено из сигнатуры функции, например:
void f(int&); // May modify the argument! Will it? Who knows...
Или даже:
void f(int const&); // May store a reference! Will it? Who knows...
Кроме того, передача по значению может даже повысить производительность, позволяя компилятору выполнять оптимизации, предотвращающие потенциальное сглаживание.
Конечно, все это в предположении, что вам фактически не нужно изменять аргумент внутри функции таким образом, чтобы побочные эффекты по этому аргументу были видны вызывающей стороне после возврата функции или хранения ссылаясь на этот аргумент.
Если это так, вам следует, конечно, пройти по ссылке и использовать соответствующую квалификацию const
.
Для более широкого обсуждения также см. fooobar.com/questions/58832/....
Ответ 2
В целом не будет каких-либо преимуществ в плане производительности, и вполне может быть стоимость исполнения. Рассмотрим этот код:
void foo(const int& a, const int& b, int& res) {
res = a + b;
res *= a;
}
int a = 1, b = 2;
foo(a, b, a);
Когда компилятор встречает такую функцию, как add(), он должен предположить, что a и res могут быть псевдонимом, как в примере вызова, поэтому без глобальных оптимизаций ему придется сгенерировать код, который загружает a, загружает b, а затем сохраняет результат + b для res, затем снова загружает и выполняет умножение, прежде чем сохранять результат обратно в res.
Если вместо этого вы написали свою функцию следующим образом:
int foo(int a, int b) {
int res = a + b;
res *= a;
return res;
}
int a = 1, b = 2;
int c = foo(a, b);
Затем компилятор может загружать a и b в регистры (или даже передавать их непосредственно в регистры), добавлять и умножать в регистры, а затем возвращать результат (который во многих соглашениях о вызовах может быть возвращен непосредственно в регистр, который был сгенерированный в).
В большинстве случаев вам действительно нужна семантика в переменной pass/return по значению версии foo, и семантика псевдонимов, которая возможна в pass/return по ссылочной версии, действительно не нуждается в поддержке. Вы можете в конечном итоге заплатить реальную штрафную пенальти, используя проход/возврат по ссылочной версии.
Чандлер Каррут дал хороший разговор, который коснулся этого в С++ Now.
Ответ 3
Может быть какая-то неясная архитектура, где это так, но я не знаю, где возвращаемые встроенные типы менее эффективны, чем передача параметра out по ссылке. Вы всегда можете проверить соответствующую сборку, если хотите.