STL Функциональный - Почему? - PullRequest
11 голосов
/ 09 марта 2012

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

Приносит ли какое-либо удобство использование функций в качестве объектов в C ++?

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

Ответы [ 4 ]

10 голосов
/ 09 марта 2012

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

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

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

  • Функциональные объекты являются интеллектуальными функциями:

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

  • Мощность общего программирования:

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

4 голосов
/ 09 марта 2012

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

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

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

Этот вопрос с веб-страницы Бьярна Страуструпа (изобретатель C ++) хорошо объясняет этот аспект.

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

3 голосов
/ 09 марта 2012

> Приносит ли удобство использование функций в качестве объектов в C ++?

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

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

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


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

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


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

C стиль:

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

C ++ (и Java) стиль ООП:

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

C ++ стиль шаблона:

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

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

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

  • Указатель на функцию и ссылка на ее закрытие в регистрах машины.
  • Обычно это не вызов функции, а GOTO-подобный прыжок.
  • Для функций не требуется стек, нет адреса для возврата назад, нет параметров или локальных переменных в стеке.
  • Функции имеют свои закрываемые закрытия, содержащие параметры, и указатель на следующую вызываемую функцию.
  • Чтобы процессор мог предсказать скачок, адрес функции должен быть загружен в регистр как можно раньше.
  • Это 1 косвенное направление с возможным прогнозом скачка; все почти так же быстро, как встроено.
2 голосов
/ 09 марта 2012

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

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

...