Reputation: 150
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);
}
});
}
Upvotes: 5
Views: 1103
Reputation: 21576
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.
Upvotes: 9
Reputation: 4429
The lambda's to which you refer are capturing state (for example the this pointer) from the class object and they need to ensure the object is still alive when they access the state. Remember those lambdas are being called asynchronously, for example when there is data ready to read. The function that instantiated the class initially and the async lambdas thus all share ownership of the class instance.
Have you read this, if not it might be helpful?
Upvotes: 1