Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asio: usage of self shared pointer in the examples

Looking through the examples of the Asio library, this one for example (for instance, line 37), I see that sometimes they create a shared pointer from this (they name it self), and capture it in a lambda where they call some asio functions, but I don't understand what the purpose of it. I don't even see it used.

So, why do they do this?


Relevant Code:

..in the server class... (where a session is created)

if (!ec)
{
    std::make_shared<session>(std::move(socket_))->start();
}

... session::start() member method:

void start()
  {
    do_read();
  }

... session::do_read() member method (where my point of interest is):

void do_read()
  {
    auto self(shared_from_this());                    // <<< ---WHY THIS??????
    socket_.async_read_some(asio::buffer(data_, max_length),
        [this, self](std::error_code ec, std::size_t length)
        {
          if (!ec)
          {
            do_write(length);
          }
        });
  }
like image 574
Hydn Avatar asked Jan 06 '23 03:01

Hydn


1 Answers

The purpose of std::enable_shared_from_this<> is to create an extra std::shared_ptr from the std::shared_ptr handle that owns the object calling shared_from_this member function.


if (!ec)
{
     std::make_shared<session>(std::move(socket_))->start();
}

The above -^^^- is where the line that creates a session. And as you can see, the std::shared_ptr that is returned by std::make_shared will be destroyed at the ;, which should also destroy the session created...

But because start() method calls do_read() which is defined as...

void do_read()
  {
    auto self(shared_from_this());
    socket_.async_read_some(asio::buffer(data_, max_length),
        [this, self](std::error_code ec, std::size_t length)
        {
          if (!ec)
          {
            do_write(length);
          }
        });
  }

That self increases the shared_ptr reference count. so the destruction of the original shared_ptr created will not destroy the object, rather, it will leave self as the reference to the created object.


Also know that a Lambda can outlive its caller... boost::asio::async_write is an asynchronous method that returns immediately after copying it's arguments. The passed lambda may not execute before you reach the end of life of your session. Hence without the additional std::shared_ptr created by shared_from_this, the destructor will run. That additional shared_ptr prevents the destructor of session from running, until the lambda function is called and it's arguments are destructed.

like image 59
WhiZTiM Avatar answered Jan 14 '23 22:01

WhiZTiM