В C ++, что означает для компилятора «встроить» объект функции? - PullRequest
15 голосов
/ 09 февраля 2010

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

Я немного сомневаюсь, что именно это означает в этом контексте ... или в любом контексте, который мне стыдно говорить. Спасибо за любую помощь!

Ответы [ 4 ]

14 голосов
/ 09 февраля 2010

Последний параметр шаблона for_each - это функтор . Functor - это то, что может быть вызвано с помощью оператора () (возможно, с аргументами). По определению, есть два отличительных типа функторов:

  1. Обычные функции, не являющиеся членами функторы.
  2. Объекты типа класса с перегруженным оператором () (так называемые функциональные объекты ) также являются функторами.

Теперь, если вы хотите использовать обычную функцию в качестве функтора для for_each, она будет выглядеть примерно так:

inline void do_something(int &i) { /* do something */ }

int main() {
  int array[10];
  std::for_each(array, array + 10, &do_something);
}

В этом случае шаблон for_each создается с [выведенными] аргументами <int *, void (*)(int &)>. Обратите внимание, что фактическим значением функтора в этом случае является указатель на функцию &do_something, передаваемый в качестве аргумента функции. С точки зрения функции for_each это значение времени выполнения. А поскольку это значение времени выполнения, вызовы функтора не могут быть встроенными. (Так же, как в общем случае невозможно встроить любой вызов, сделанный через указатель на функцию).

Но если вместо этого мы используем функциональный объект, код может выглядеть следующим образом

struct do_something {
  void operator()(int &i) { /* do something */ }
}; 

int main() {
  int array[10];
  std::for_each(array, array + 10, do_something());
}

В этом случае шаблон for_each создается с [выведенными] аргументами <int *, do_something>. Звонки на функтор изнутри for_each будут направлены на do_something::operator(). Цель для вызова известна и исправлена ​​во время компиляции. Поскольку целевая функция известна во время компиляции, вызов может быть легко встроен.

В последнем случае у нас, конечно, также есть значение времени выполнения, переданное в качестве аргумента for_each. Это [возможно, «фиктивный» временный] экземпляр класса do_something, который мы создаем при вызове for_each. Но это значение времени выполнения не влияет на цель для вызова (если operator () не является виртуальным), поэтому оно не влияет на встраивание.

6 голосов
/ 09 февраля 2010

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

Компилятор часто не может этого сделать, если передан указатель на функцию.

3 голосов
/ 09 февраля 2010

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

3 голосов
/ 09 февраля 2010

Подстановка означает просто замену каждого вызова этой функции на тело этой функции напрямую.

Это оптимизация для небольших функций, поскольку она снижает накладные расходы при переходе к новой функции, а затем возвращает.

...