Подтвердить что ты не робот

Будет ли хороший компилятор С++ оптимизировать ссылку?

Я хочу написать функцию шаблона, которая делает что-то с std::stack<T> и экземпляр T, например:

template<class StackType> inline
bool some_func( StackType const &s, typename StackType::value_type const &v ) {
  // ...
}

Причина, по которой я передаю v по ссылке, конечно, должна быть оптимизирована для случая, когда StackType::value_type является struct или class и не копирует весь объект по значению.

Однако, если StackType::value_type является "простым" типом типа int, то, конечно, лучше просто передать его по значению.

Вопрос: для типа, такого как int, который станет int const& в качестве формального аргумента в вышеприведенной функции, будет ли компилятор оптимизировать ссылку и просто передать ее по значению?

4b9b3361

Ответ 1

Хотя я на самом деле не тестировал никаких компиляторов для этого, я сомневаюсь. Вы предполагаете, что передача ссылки const не отличается от просто передачи значения, но это не так, и компилятор не должен предполагать, что это так.

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

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

Возможно, вам может быть интересна библиотека Boost . Он предоставляет тип шаблона call_traits<T>::param_type, который является ссылкой на константу для "больших" типов, которые вы не хотите копировать, и значение для "малых" типов, где копия будет более эффективной. В основном, что вы хотите, чтобы компилятор выполнял неявно, вы можете явно указывать свой код.

Ответ 2

Всякий раз, когда компилятор способен встроить, результирующая кросс-процедурная оптимизация устраняет затраты на поиск и передачу адреса.

Для не-встроенных вызовов функций ссылка, вероятно, будет реализована как указатель, а не по значению.

Ответ 3

Я смотрю в вариантах оптимизации gcc здесь http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

И на самом деле есть вариант для вашего случая:

-fipa-SRA

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

Включено на уровнях -O2, -O3 и -Os

Насколько я знаю, -O2 - обычный вариант для сборки релиза на Linux.

Итак, короткий ответ: один из хороших компиляторов делает

Ответ 4

Это 64-битный компилятор MSVC2010, полная оптимизация:

int foo( int i )
{
 int a = i + i;

 return ( a );
}
//Disassembly:
//00000001`3ff11c50 8d0409          lea     eax,[rcx+rcx]
//00000001`3ff11c53 c3              ret

int bar( int const & i )
{
 int a = i + i;

 return ( a );
}
//Disassembly:
//00000001`3ff11c10 8b01            mov     eax,dword ptr [rcx]
//00000001`3ff11c12 03c0            add     eax,eax
//00000001`3ff11c14 c3              ret

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

Передача экземпляров "малых" классов (например, класс имеет только элемент данных int и тривиальный конструктор, побитовое копирование-конструктор и т.д.) быстрее по значению. Компилятор оптимизирует его, по сути, просто передавая копию int. Таким образом, вы можете перегружать свою функцию, как указал Уазард, используя некоторые черты типа. Что-то вроде этого:

template< typename PType >
PType Func( typename std::enable_if< ( sizeof( PType ) > sizeof( size_t ) ), PType const & >::type f )
{
 //large things: reference
}

template< typename PType >
PType Func( typename std::enable_if< ( sizeof( PType ) <= sizeof( size_t ) ), PType  >::type f )
{
 //small things: value
}