Я также вижу, что этот шаблон часто используется, и (благодаря @Tanner) я могу понять, почему он используется, когда io_service
выполняется в нескольких потоках. Тем не менее, я думаю, что у него все еще есть проблемы со сроком службы, поскольку он заменяет потенциальный сбой потенциальной утечкой памяти / ресурсов ...
Благодаря boost :: bind любые обратные вызовы, привязанные к shared_ptrs, становятся «пользователями» объекта (увеличивая use_count объектов), поэтому объект не будет удален до тех пор, пока не будут вызваны все невыполненные обратные вызовы.
Обратные вызовы к функциям boost :: asio :: async * вызываются всякий раз, когда вызывается отмена или закрытие соответствующего таймера или сокета. Обычно вы просто выполняете соответствующие вызовы отмены / закрытия в деструкторе, используя любимый Страуструпом шаблон RAII; Работа выполнена.
Однако деструктор не будет вызываться, когда владелец удаляет объект, потому что обратные вызовы по-прежнему содержат копии shared_ptrs, и поэтому их use_count будет больше нуля, что приведет к утечке ресурсов. Утечки можно избежать, сделав соответствующие вызовы отмены / закрытия перед удалением объекта. Но это не так надежно, как использование RAII и выполнение вызовов отмены / закрытия в деструкторе. Обеспечение освобождения ресурсов всегда, даже при наличии исключений.
Шаблон, соответствующий RAII, заключается в использовании статических функций для обратных вызовов и передаче weak_ptr для boost :: bind при регистрации функции обратного вызова, как в примере ниже:
class Connection : public boost::enable_shared_from_this<Connection>
{
boost::asio::ip::tcp::socket socket_;
boost::asio::strand strand_;
/// shared pointer to a buffer, so that the buffer may outlive the Connection
boost::shared_ptr<std::vector<char> > read_buffer_;
void read_handler(boost::system::error_code const& error,
size_t bytes_transferred)
{
// process the read event as usual
}
/// Static callback function.
/// It ensures that the object still exists and the event is valid
/// before calling the read handler.
static void read_callback(boost::weak_ptr<Connection> ptr,
boost::system::error_code const& error,
size_t bytes_transferred,
boost::shared_ptr<std::vector<char> > /* read_buffer */)
{
boost::shared_ptr<Connection> pointer(ptr.lock());
if (pointer && (boost::asio::error::operation_aborted != error))
pointer->read_handler(error, bytes_transferred);
}
/// Private constructor to ensure the class is created as a shared_ptr.
explicit Connection(boost::asio::io_service& io_service) :
socket_(io_service),
strand_(io_service),
read_buffer_(new std::vector<char>())
{}
public:
/// Factory method to create an instance of this class.
static boost::shared_ptr<Connection> create(boost::asio::io_service& io_service)
{ return boost::shared_ptr<Connection>(new Connection(io_service)); }
/// Destructor, closes the socket to cancel the read callback (by
/// calling it with error = boost::asio::error::operation_aborted) and
/// free the weak_ptr held by the call to bind in the Receive function.
~Connection()
{ socket_.close(); }
/// Convert the shared_ptr to a weak_ptr in the call to bind
void Receive()
{
boost::asio::async_read(socket_, boost::asio::buffer(read_buffer_),
strand_.wrap(boost::bind(&Connection::read_callback,
boost::weak_ptr<Connection>(shared_from_this()),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
read_buffer_)));
}
};
Примечание: read_buffer_
сохраняется как shared_ptr
в классе Connection и передается в функцию read_callback
как shared_ptr
.
Это необходимо для того, чтобы гарантировать, что там, где несколько io_services
выполняются в отдельных задачах, read_buffer_
не удаляется до тех пор, пока после не будут завершены другие задачи, то есть когда будет вызвана функция read_callback
.
person
kenba
schedule
27.10.2013
static
вспомогательные функции, которые явно принимаютshared_ptr
и вызывают функцию-член. Но я вижу так много кода, который делает это таким образом, я не могу поверить, что все это сломано. Тем не менее, я тоже не вижу, где это задокументировано. - person David Schwartz   schedule 06.07.2012