Bill Bill - 11 months ago 123
C++ Question

boost::asio::strand wrap causing shared_ptr from shared_from_this to become NULL

When I tried to use

function, it seems to cause the
that came from
to become NULL, so when it is executed the second time, it will cause the program to crash.

However, this only happens if the function that was binded takes no arguments.

After setting the watch point and checking the callstack, this behavior seems to be caused by move constructor of
swapping value, which originated from

My question is, how should I properly use
to avoid this from happening?

Below is a simple sample to show you what I meant:

class object : public boost::enable_shared_from_this<object> {
: service(new boost::asio::io_service),
work(new boost::asio::io_service::work(*service)),
value(0) {}

void workerThread() {

void run() {
func_int = strand.wrap(boost::bind(&object::handler_int, shared_from_this(), _1));
func_void = strand.wrap(boost::bind(&object::handler_void, shared_from_this()));

std::thread thread(boost::bind(&object::workerThread, this));


func_void(); // Will crash due to shared_ptr being NULL, hence "value" cannot be accessed in handler_void


void handler_int(int parameter) {
cout << "handler_int: " << value << endl;

void handler_void() {
cout << "handler_void: " << value << endl;

boost::shared_ptr<boost::asio::io_service> service;
boost::shared_ptr<boost::asio::io_service::work> work;
boost::asio::strand strand;
std::function<void(int)> func_int;
std::function<void(void)> func_void;
int value;

int main(int argc, char *argv[]) {
boost::shared_ptr<object> obj(new object());
return 0;

Answer Source

This is due to a misunderstanding of what wrap does. This caught me out too recently. I wrote to the author of asio for clarification. What he told me surprised me.

wrap returns a 'wrapped_handler' but contrary to what you might expect, this is not a function object which performs a dispatch under the covers.

It is actually an object that contains the handler you bound plus a reference to the executor. Asio io objects use this information when completing async operations in order to execute the handler in the correct context.

Confusingly, this wrapped_handler also has an operator(). What this does is merely execute the bound function. It does not post or dispatch the function. In my view this operator() should not exist. I have mailed Christopher Kohlhoff expressing this view. I have not had a reply.

you can prove this by replacing this:


with this:

service->post(strand->wrap(boost::bind(&object::handler_int, shared_from_this(), 1)));

for each of the invocations of the bound member function. You can then test that they are executing in the strand.

Note that it would not matter which io_service you posted/dispatched them to. They would be sent straight to the strand with which they have been associated by wrap.

Finally, on asio and style.

You may want to address the ownership of io_service/strand/work objects by shared_ptr. This is always un-necessary. An io_service is a fundamental component of an application - the central message loop. It will not have an indeterminate lifetime. Neither will the work or the strand. Provided you end its lifetime with:


All will be well.