Являются ли компиляторы достаточно умными, чтобы оптимизировать функторы с элементами, аналогичными аргументам статического метода? - PullRequest
1 голос
/ 23 февраля 2012

Я заинтересован в написании исходного кода для нескольких компиляторов (GCC, MSVC, Clang).Я видел два шаблона для передачи функций в качестве аргументов времени компиляции, и мне любопытно, являются ли компиляторы, как правило, достаточно умными, чтобы признать, что они эквивалентны, или я слишком много спрашиваю.Вот стиль STL, передающий объект функтор:

  template<class InputIterator, class Predicate>
  InputIterator find_if ( InputIterator first, InputIterator last, Predicate pred )
  {
    for ( ; first!=last ; first++ ) if ( pred(*first) ) break;
    return first;
  }

А вот альтернативный стиль:

  template<class InputIterator, class Predicate, class PredData>
  InputIterator find_if ( InputIterator first, InputIterator last, PredData data )
  {
    for ( ; first!=last ; first++ ) if ( Predicate::eval(*first, data) ) break;
    return first;
  }

В стиле STL ваш класс Predicate обычно содержит в качестве членов любые данные, которые ему нужныи вы вызываете operator () для оценки предиката.В альтернативном стиле у вас никогда нет объекта Predicate, скорее он содержит статический метод, который принимает проверяемый элемент, и данные передаются в качестве аргумента, а не сохраняются в качестве члена в Predicate.

Iесть несколько опасений, использующих стиль STL:

  1. Если предикат - слово или меньше, будет ли компилятор достаточно умен, чтобы передать его регистром?В альтернативном стиле слово будет аргументом, поэтому компилятору не нужно ничего выводить.
  2. Если предикат пуст, будет ли он достаточно умен, чтобы избежать его создания и передачи?В альтернативном стиле Predicate никогда не создается.

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

Ответы [ 2 ]

2 голосов
/ 23 февраля 2012

Из моего личного опыта работы с gcc (g ++) современные компиляторы абсолютно способны оптимизировать функторы.Единственный случай, когда это не может быть правдой, это когда функтор находится в другом модуле компиляции.

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

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

Наконец, Херб Саттер сказал в одной из своих презентаций(при сборке, я думаю), что стиль C ++ по сравнению со стилем C добавляет только 3% накладных расходов, что ничто по сравнению с его большей безопасностью.

1 голос
/ 23 февраля 2012

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

В C ++ 11 есть семантика перемещения, которая может оптимизировать копию объекта Predicate. Поскольку это в стандарте, все компиляторы должны реализовать эту же оптимизацию, и первый стиль будет иметь близкую производительность, как и второй.

Еще один аргумент в пользу стиля STL заключается в том, что, будучи общим шаблоном, у вас, вероятно, больше шансов на оптимизацию компилятора, поскольку производители компиляторов будут ориентироваться на эти шаблоны использования.

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

...