Лучшие практики асинхронного вызова C++

Я работаю с boost::asio. Я написал класс, отвечающий за асинхронное чтение из сокета. В моем приложении io_service может останавливаться и запускаться много раз за один запуск приложения. Поэтому я должен беспокоиться об утечке памяти, когда служба остановлена. Я пришел к двум решениям:

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

  2. Умный указатель привязан к обратному вызову. Пример здесь: http://pastebin.com/p8nQ5NFi

Сейчас я использую второе решение, но как бы я ни чувствовал, я изобрел колесо. Какова общая практика для очистки буфера в асинхронном вызове? Есть ли скрытые проблемы в моем подходе?

1 ответ

Решение

shared_ptr Подход довольно распространен. Однако вместо прохождения shared_ptr в качестве дополнительного аргумента bind, можно пройти shared_ptr в качестве объекта экземпляра вместо this,

boost::shared_ptr< my_class > ptr( this );

boost::asio::async_read( stream, buffer, 
  boost::bind( &my_class::read_handler, ptr, 
     boost::asio::placeholders::error
     boost::asio::placeholders::bytes_transferred ) );

Часто, так как экземпляр будет управляться через shared_ptrкоторый может или не может быть в контексте this, это хорошая идея, чтобы использовать Boost.SmartPointer's enable_shared_from_this, Когда класс наследует отboost::enable_shared_from_thisэто обеспечиваетshared_from_this()функция-член, которая возвращает действительный shared_ptrэкземпляр для this,

class my_class: public boost::enable_shared_from_this< my_class >
{
  void read()
  {
     boost::asio::async_read( stream, buffer, 
       boost::bind( &my_class::read_handler, shared_from_this(), 
          boost::asio::placeholders::error
          boost::asio::placeholders::bytes_transferred ) );
  }
};

boost::shared_ptr< my_class > foo( new my_class() );
foo->read();

В этом фрагментеfoo.get()а такжеfoo->shared_from_this()оба указывают на один и тот же экземпляр. Это помогает избежать трудностей с обнаружением утечек памяти. Например, в исходном примере кода утечка памяти происходит в Protocol::AsyncReadMessage если AsyncReadHandler копирует конструктор бросает при попытке вызвать AsyncReadMessage, Асинхронный TCP-сервер Boost.Asio для дневного времени и многие примеры показывают enable_shared_from_this используется в Boost.Asio. Для более глубокого понимания этот вопрос конкретно охватывает асинхронные функции Boost.Asio и shared_ptr,


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

Другие вопросы по тегам