Функциональность STL - почему?

В стандартной библиотеке шаблонов С++ есть "функциональная" часть, в которой многие классы перегружали свой оператор ().

Имеет ли смысл использовать функции как объекты в С++?

Почему мы не можем просто использовать указатель на функцию? Любые примеры?

Ответ 1

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

  • Лучшая производительность:

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

  • Функциональные объекты - это интеллектуальные функции:

Объекты функций могут иметь другие функции-члены и атрибуты. Это означает, что объекты-функции имеют состояние. Фактически, одна и та же функция, представленная функциональным объектом, может иметь разные состояния одновременно. Это невозможно для обычных функций. Другим преимуществом функциональных объектов является то, что вы можете инициализировать их во время выполнения, прежде чем использовать/вызывать их.

  • Сила общего программирования:

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

Ответ 2

Почему мы не можем просто использовать указатель на функцию? Любые примеры?

Использование указателя функции стиля C не может использовать преимущество встраивания. Указатель функции обычно требует дополнительной косвенности для поиска.
Однако, если operator () перегружено, то для компилятора очень легко компилировать код inline и сохранить дополнительный вызов, поэтому увеличить производительность.

Другим преимуществом перегруженного operator () является то, что можно создать функцию, которая неявно рассматривает объект функции как аргумент; нет необходимости передавать его как отдельную функцию. Мало ручная кодированная программа, меньше ошибок и улучшенная читаемость.

Этот вопрос на веб-странице Bjarne Stroustrup (С++ inventor) объясняет этот аспект.

Библиотека С++ Standard (Template) использует функциональное программирование с перегруженным operator (), если это необходимо.

Ответ 3

Имеет ли смысл использовать функции как объекты в С++?

Да: механизм шаблонов С++ позволяет использовать все другие стили программирования C/С++ (стиль C и стиль ООП, см. ниже).

Почему мы не можем просто использовать указатель на функцию? Любые примеры?

Но мы можем: простой C-указатель функции - это объект с хорошо определенным оператором(). Если мы создадим библиотеку, мы не хотим принуждать кого-либо использовать этот стиль указателя C, если это нежелательно. Как правило, это нежелательно, так как все/все могут использовать/использовать стиль ООП; см. ниже.


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

В С++ все объекты с желаемыми свойствами можно рассматривать как объекты. В этом случае простым указателем функции C также является объект. Это не означает, что парадигмы ООП используются, когда это нежелательно; это просто правильный способ использования механизма шаблона.


Чтобы понять различия в производительности, сравните стили/парадигмы программирования (-язык) и их возможные оптимизации:

Стиль C:

  • Функциональный указатель с его закрытием ("this" в ООП, указатель на некоторую структуру) в качестве первого параметра.
  • Для вызова функции сначала необходимо получить адрес функции.
  • Это 1 косвенность; нет возможности вставки.

Стиль OOP С++ (и Java):

  • Ссылка на объект, полученный из класса с виртуальными функциями.
  • Ссылка - 1-й указатель.
  • Указатель на виртуальную таблицу - это второй указатель.
  • Указатель функций в виртуальной таблице - это третий указатель.
  • Это 3 направления; нет возможности вставки.

Стиль шаблона С++:

  • Копирование объекта с функцией().
  • Нет виртуальной таблицы, так как тип этого объекта известен во время компиляции.
  • Адрес функции известен во время компиляции.
  • Это 0 указаний; inlining возможно.

Шаблоны С++ достаточно универсальны, чтобы позволить двум другим стилям выше, а в случае вставки они могут даже превосходить...

скомпилированные функциональные языки: (исключая JVM и Javascript как целевые платформы из-за отсутствия "правильных хвостовых вызовов" )

  • Указатель функций и ссылка на его закрытие в машинных регистрах.
  • Обычно нет функции "call", но GOTO как прыжок.
  • Функции не нуждаются в стеке, нет адреса для перехода назад, никаких параметров и локальных переменных в стеке.
  • У функций есть свои собираемые для мусора замыкания (-ы), содержащие параметры, и указатель на следующую вызываемую функцию.
  • Для того чтобы ЦП мог предсказать скачок, адрес функции должен быть загружен в регистр как можно раньше.
  • Это 1 косвенность с возможным предсказанием прыжка; все почти так же быстро, как указано.

Ответ 4

Основное отличие состоит в том, что объекты функции более мощные, чем простые указатели функций, поскольку они могут содержать состояние. Большинство алгоритмов используют функции шаблонов, а не простые указатели функций, которые позволяют использовать мощные конструкции в качестве связующих, которые вызывают функции с разными сигнатурами, заполняя дополнительные аргументы значениями, хранящимися на функторе, или более новыми лямбдами в С++ 11. Как только алгоритмы предназначены для использования функторов, имеет смысл предоставить набор предопределенных общих функций функций в библиотеке.

Кроме того, существуют потенциальные преимущества, заключающиеся в том, что в большинстве случаев эти функторы являются простыми классами, для которых компилятор имеет полное определение и может выполнять инкрустацию вызовов функций, повышая производительность. Вот почему std::sort может быть намного быстрее, чем qsort из библиотеки C.