Виталий Ткаченко - Обратные вызовы в C++
- Название:Обратные вызовы в C++
- Автор:
- Жанр:
- Издательство:Array SelfPub.ru
- Год:2021
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Виталий Ткаченко - Обратные вызовы в C++ краткое содержание
Обратные вызовы в C++ - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Сложность разработки . При проектировании шаблонного кода операции зачастую задаются в декларативном виде, что приближает их к функциональному стилю. Использование пакетов параметров требует изощренных техник, весьма непохожих на классические приемы программирования.
Сложность понимания . Код, написанный с помощью шаблонов, гораздо труднее анализировать, чем обычный. В этом можно убедиться, просмотрев, к примеру, исходный код стандартной библиотеки STL.
Недружественность компилятора. Сообщения об ошибках, генерируемые при компиляции шаблонов, зачастую сложны и непонятны. Когда ошибка показывается где-то в недрах шаблонного кода, очень трудно бывает догадаться, возникает ли проблема из-за некорректной реализации этого кода либо из-за того, что структура данных, подставляемая в шаблон, не реализует предполагаемый интерфейс (например, требуется перегрузка некоторых операторов).
Тщательное тестирование. Шаблоны подчиняются концепции «компиляция по требованию», т. е. компилируются только те функции и методы, которые используются в коде. Поэтому, чтобы убедиться в отсутствии синтаксических и семантических ошибок, следует покрывать вызовами все функции и методы, объявленные в шаблоне. Причем желательно это делать на некотором наборе предполагаемых типов данных.
Большое время компиляции . Во-первых, компилятор осуществляет генерацию кода при каждом инстанциировании шаблона конкретным типом. Во-вторых, шаблоны для одних и тех же типов, инстанциируемые в разных участках программы, будут компилироваться заново. И, в-третьих, много времени тратится на компиляцию включаемых файлов: например, при каждом включении заголовочных файлов стандартной библиотеки все внутренние реализации шаблонов в этих файлах должны быть скомпилированы.
Склонность к разрастанию программного кода. Для каждого используемого типа будет сгенерирован отдельный код. Представим, к примеру, что мы используем шаблонную функцию с входным аргументом – числом, тип которого задается параметром шаблона. Если мы будем вызывать эту функцию с аргументами различных типов, допустим, char, short, int, long, для каждого типа будет сгенерирована отдельная функция, несмотря на то что используемые типы эквивалентны и можно обойтись одним-единственным типом long. Аналогичная ситуация возникает при специализации шаблонов: даже если мы делаем частичную специализацию c целью изменить поведение одного-единственного метода, нам придется повторить весь код, используемый в общей специализации.
4.7.2. Ограничения шаблонов
В общем-то, рассмотренные недостатки не так уж значительны, и преимуществ у шаблонов значительно больше. Тем не менее, они имеют фундаментальное ограничение, вытекающие из их внутренней природы: шаблоны не создают предварительно откомпилированного кода. По большому счету шаблон представляет собой не сам код, а правила для генерации кода. Пока шаблон не инстанциирован, его код отсутствует; после инстанциирования последний генерируется только для тех методов и функций, которые были вызваны. Из указанного ограничения вытекают следующие выводы.
Интерфейс шаблона не может быть отделен от реализации . И объявление шаблона, и его реализация должны находиться в одной области видимости (модель включения). Таким образом, при изменениях в реализации шаблона все компоненты, которые его используют, должны быть перекомпилированы.
Шаблоны не могут поставляться в виде статических или динамических библиотек , они должны поставляться только в виде исходного кода. Никакие сторонние приложения (за исключением компиляторов C++, разумеется) не могут использовать функциональность, реализованную на базе шаблонов.
По вышеуказанным причинам, 29 29 Здесь необходимо уточнить: речь идет только об интерфейсе API, т. е. его видимой части. В реализации API шаблоны использовать можно и нужно.
С помощью шаблонов невозможно реализовать интерфейсы API.
4.8. Итоги
Шаблоны обеспечивают параметрический полиморфизм, что позволяет писать обобщенный код, реализующий заданную функциональность без привязки к типам данных.
Инициатор для синхронных вызовов реализуется с помощью шаблонов функций, асинхронных – с помощью шаблонов классов.
В реализации шаблона инициатора тип объекта вызова задается параметром. Поскольку разные типы объектов требуют различное число параметров и используют неодинаковый синтаксис, для сохранения единой реализации используется преобразование вызовов.
Функциям, реализующим алгоритмы, зачастую требуются различные операции над данными. Поскольку в обобщенном коде типы данных заранее не известны, для реализации операций используются предикаты.
В асинхронных вызовах для каждого типа аргумента приходится инстанциировать соответствующий инициатор. Использование универсального аргумента позволяет реализовать единый класс для любых типов аргументов, однако в некоторых случаях это может привести к падению производительности.
В стандартной библиотеке STL имеются мощные средства для организации вызовов, реализующие универсальный аргумент, вызов методов класса, перенаправление вызовов.
Шаблонам присущи недостатки, большинство из которых незначительны и не перевешивают их достоинств. Однако шаблоны не предполагают предварительно откомпилированного кода, и по этой причине не могут использоваться в интерфейсах API.
5. Распределение вызовов
5.1. Постановка задачи
Под распределением вызовов понимается техника, в которой при вызове единственной функции осуществляется выполнение множества вызовов через соответствующие аргументы.
Графически задача распределения вызовов показана на Рис. 21. Компонент, осуществляющий вызов, называется источником; аргументы вызова называются получателями; компонент, осуществляющий распределение вызовов, называется распределитель; код, запускающий вызовы, называется распределяющая функция. При необходимости дополнительно в вызов могут передаваться какие-либо данные.
Распределитель может быть реализован в виде функции либо класса. Если распределитель реализован в виде функции, то он сам представляет собой распределяющую функцию. Если распределитель реализован в виде класса, то распределяющая функция представляет собой метод класса либо перегруженный оператор.

Рис. 21. Распределение вызовов
Как видим, постановка задачи звучит достаточно просто. Зачем же тогда ей посвящен отдельный раздел? Во-первых, распределение вызовов имеет важное прикладное значение: оно используется в самых различных приложениях, таких, как обработка команд, оповещение о событиях, синхронизация операций и др. Во-вторых, задача распределения вызовов совсем не такая простая, как это может показаться из формального описания. Для ее решения используются изощренные техники, призванные обеспечивать максимальную эффективность для самых различных требований.
Читать дальшеИнтервал:
Закладка: