Для «входных» параметров передавайте дешёво копируемые типы по значению, остальные — по ссылке на `const`
Причина
Оба варианта сообщают вызывающему, что функция не изменит аргумент, и оба допускают инициализацию rvalue.
Что считается «дешёвым для копирования», зависит от архитектуры машины, но два или три слова (double, указатели, ссылки) обычно лучше передавать по значению. Когда копирование дёшево, ничто не превосходит простоту и безопасность копирования, а для небольших объектов (до двух-трёх слов) это также быстрее передачи по ссылке, поскольку не требует дополнительного обращения через указатель.
Пример
void f1(const string& s); // OK: передача по ссылке на const; всегда дёшево
void f2(string s); // плохо: потенциально дорого
void f3(int x); // OK: непобедимо
void f4(const int& x); // плохо: накладные расходы при доступе в f4()
Для продвинутых случаев (только), когда реально нужна оптимизация для rvalue, передаваемых в «только входные» параметры:
- Если функция безусловно перемещает аргумент, принимайте его по
&&. См. F.18. - Если функция хранит локальную изменяемую копию аргумента только для собственного использования, передача по значению допустима.
- Если функция хранит копию аргумента для передачи другому получателю (другой функции или нелокальному месту хранения), в дополнение к передаче по
const&(для lvalue) добавьте перегрузку, принимающую параметр по&&(для rvalue), и в теле выполнитеstd::moveк месту назначения. По существу это перегрузка «будет перемещено»; см. F.18. - В особых случаях, например при нескольких параметрах «вход + копия», рассмотрите использование совершенной передачи. См. F.19.
Пример
int multiply(int, int); // только входные int-ы, передача по значению
// суффикс — только входной, но не такой дешёвый как int, передача по const&
string& concatenate(string&, const string& suffix);
void sink(unique_ptr<widget>); // только входной, и передаёт владение widget
Избегайте «эзотерических техник», таких как передача аргументов как T&& «для эффективности». Большинство слухов о преимуществах производительности при передаче через && ложны или ненадёжны (но см. F.18 и F.19).
Примечания
На ссылку можно рассчитывать, что она ссылается на допустимый объект (языковое правило). Не существует (законной) «нулевой ссылки». Если нужна концепция необязательного значения, используйте указатель, std::optional или специальное значение, обозначающее «нет значения».
Контроль
Предложить использовать ссылку на const.
- (Простой) ((Основа)) Предупреждать, если параметр, передаваемый по значению, имеет размер больше
4 * sizeof(void*). - (Простой) ((Основа)) Предупреждать, если параметр, передаваемый по ссылке на
const, имеет размер меньше или равный2 * sizeof(void*). Предложить передавать по значению. - (Простой) ((Основа)) Предупреждать, если параметр, передаваемый по ссылке на
const, используется сmove. - (Не простой) Замечание: Более строгий контроль будет зависеть от характеристик производительности целевой архитектуры.
Исключение
Для выражения совместного владения с помощью типов shared_ptr, следуйте R.34 или R.36, в зависимости от того, безусловно ли функция принимает ссылку на аргумент.