Виталий Ткаченко - Обратные вызовы в C++

Здесь есть возможность читать онлайн «Виталий Ткаченко - Обратные вызовы в C++» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Год выпуска: 2021, Издательство: Array SelfPub.ru, Жанр: Программирование, на русском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

Обратные вызовы в C++: краткое содержание, описание и аннотация

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

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

Обратные вызовы в C++ — читать онлайн бесплатно полную книгу (весь текст) целиком

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Обратные вызовы в C++», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

{

int operator() (int eventID) {return 10;}

};

struct FOVoid

{

void operator() (int eventID) { /*do something*/ }

};

struct SResult

{

unsigned int code;

const char* description;

};

SResult ExternalReturn(int eventID)

{

return SResult{ 1, "this is an error" };

}

void ExternalVoid(int eventID)

{

}

int main()

{

int eventID = 0;

FOReturn foRet;

FOVoid foVoid;

auto lambdaRet = [](int eventID) { return 0.0; };

auto lambdaVoid = [](int eventID) {};

using FunPtrRet = SResult(*)(int);

using LambdaTypeRet = decltype(lambdaRet);

using FunPtrVoid = void(*)(int);

using LambdaTypeVoid = decltype(lambdaVoid);

StaticDistributor distributor1(foRet, ExternalReturn, lambdaRet); // (1)

StaticDistributor distributor2(foVoid, ExternalVoid, lambdaVoid); // (2)

auto results = distributor1(eventID);

distributor2(eventID);

}

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

5.6. Динамический набор получателей

5.6.1. Распределение в динамическом наборе

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

Итак, поскольку количество объектов заранее не определено, для их хранения необходим динамический контейнер. Однако он не может хранить объекты непосредственно, поскольку они могут иметь разные типы, а динамический контейнер работает с данными одного строго определенного типа. Выходом будет хранить универсальные аргументы, а уже в них сохранять объекты вызова. Структурная схема изображена на Рис. 24.

Рис 24 Структурная схема распределителя для динамического набора получателей - фото 39

Рис. 24. Структурная схема распределителя для динамического набора получателей

Оптимальным решением будет реализация распределителя в виде класса, который, кроме выполнения распределения, будет поддерживать операции с контейнером. Конечно же, проектировать динамический контейнер и универсальный аргумент не нужно – в STL имеется все необходимое. Контейнер, в общем-то, можно использовать любой, а на роль универсального аргумента нет ничего лучше, чем std::function. Реализация приведена в Листинг 81.

Листинг 81. Распределитель для динамического набора получателей

template class DynamicDistributor; // (1)

template // (2)

class DynamicDistributor

{

public:

template

void addCallObject(CallObject object) // (3)

{

callObjects.push_back(object);

}

void operator ()(ArgumentList… arguments) // (4)

{

for (auto& callObject : callObjects)

{

callObject(arguments…);

}

}

private:

std::list< std::function > callObjects; // (5)

};

В строке 1 объявлена общая специализация шаблона. Реализация класса здесь отсутствует, поскольку для каждой сигнатуры она будет различной. В строке 2 объявлен шаблон для частичной специализации, в котором два аргумента: тип возвращаемого значения и пакет параметров, передаваемых на вход вызова. Подобную конструкцию мы использовали, когда рассматривали настройку сигнатуры для универсального аргумента (п. 4.5.2).

В строке 3 объявлен метод, который добавляет объект вызова в контейнер, сам контейнер объявлен в строке 5. Тип контейнера мы выбираем список, поскольку он не перемещает элементов при вставке/удалении, а произвольный доступ здесь не требуется. Типом хранимых данных в контейнере является объект std::function, аргументы которого задаются исходя из параметров в объявлении шаблона класса.

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

5.6.2. Получение возвращаемых значений

Как получить возвращаемые значения для динамического набора? На момент вызова распределяющей функции количество получателей может быть любым, и, соответственно, число возвращаемых значений заранее не определено. Использовать динамический контейнер как возвращаемое значение функции является плохой идеей: во-первых, заполнение контейнера и создание его копии в стеке требует значительного расхода времени и увеличивает фрагментацию памяти; во-вторых, если возвращаемое значение не используется, то все вышеописанное будет работать «вхолостую», выполняя совершенно ненужные операции. Использовать контейнер как входной параметр – это тоже идея не очень: мы вынуждаем привязаться к контейнеру определенного типа, а если нам результаты нужно хранить в других структурах? А если нам вообще их не нужно хранить, а нужно всего лишь проверить? Вопросы, вопросы… Можно предложить следующее решение: для возврата результата использовать обратный вызов, а пользователь сам решает, что делать с возвращаемыми значениями. Реализация приведена в Листинг 82.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Похожие книги на «Обратные вызовы в C++»

Представляем Вашему вниманию похожие книги на «Обратные вызовы в C++» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Отзывы о книге «Обратные вызовы в C++»

Обсуждение, отзывы о книге «Обратные вызовы в C++» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x