производительность — Могу ли я позволить компилятору C ++ решать, передавать ли по значению или по ссылке?

Посмотрите на этот гипотетический заголовочный файл:

template <class T>
class HungryHippo {
public:
void ingest(const T& object);
private:
...
}

Теперь для HungryHippo<string> имеет смысл, что вы хотели бы ingest ссылки на строки — копирование строки может быть очень дорогим! Но для HungryHippo<int> это делает намного меньше смысла. Проходя int напрямую может быть очень дешевым (большинство компиляторов делают это в реестре), но передавая ссылку на int это лишний ненужный уровень косвенности. Это все относится и к возвращаемым значениям.

Есть ли способ предложить компилятору «эй, я не собираюсь изменять аргумент, поэтому вы решить, передать ли по значению или по ссылке, в зависимости от того, что, по вашему мнению, лучше «?

Некоторые вещи, которые могут быть актуальны:

  • Я могу подделать этот эффект вручную, написав template <class T, bool PassByValue> class HungryHippo а затем специализируется на PassByValue, Если бы я хотел стать по-настоящему модным, я мог бы даже сделать вывод PassByValue основанный на sizeof(T) а также std::is_trivially_copyable<T>, В любом случае, это большая дополнительная работа, когда реализации будут выглядеть примерно одинаково, и я подозреваю, что компилятор может гораздо лучше решить, передавать ли его по значению, чем я.
  • Libc ++ Похоже, что проект решает эту проблему путем включения большого количества функций, чтобы компилятор мог сделать выбор на один уровень выше, но в этом случае, скажем, реализацию ingest довольно сложный и не стоит встраивать. Как объяснено в комментариях, все функции шаблона inline по умолчанию.

14

Решение

boost::call_traits Заголовок имеет дело именно с этим вопросом. Проверьте это Вот.

В частности, call_traits<T>::param_type Опция включает в себя следующее описание:

Если T небольшой встроенный тип или указатель, то param_type определено
как T const, вместо T const&, Это может улучшить способность
компилятор для оптимизации циклов в теле функции, если они зависят
по переданному параметру семантика переданного параметра
в остальном без изменений (требуется частичная специализация).

В вашем случае вы могли бы определить ingest следующее:

template <class T>
class HungryHippo {
public:
void ingest(call_traits<T>::param_type object);
// "object" will be passed-by-value for small
// built-in types, but passed as a const reference
// otherwise
private:
...
};

Будет ли это на самом деле иметь большое значение в вашей реальной комбинации кода / компилятора, я не уверен. Как всегда, вам нужно выполнить некоторые реальные тесты и посмотреть, что произойдет …

8

Другие решения

В то время как уловки, такие как повышение упоминалось call_traits<T> делать то, что они утверждают, что в этом случае, я думаю, вы предполагаете, что компилятор еще не делает эту оптимизацию в наиболее важных случаях. В конце концов, это тривиально. Если вы принимаете const T& а также sizeof(T) <= sizeof(void*)инварианты, навязанные C ++ ссылочной семантикой, позволяют компилятору просто подставлять значение по всему телу функции, если это выигрыш. Если это не так, ваши наихудшие издержки — разыменование указателя на аргумент в прологе функции.

0

По вопросам рекламы [email protected]