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);
}
});
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With