1

I would like to start a thread with a class which contains non-copyable members. In order to communicate with the thread I would like to create a shared pointer from the object before I move it into the thread.

Does the move constructor invalidate the shared pointer? If so, what is the elegant c++ way of doing this? One solution would be to wrap MessageClient into a shared pointer, but that hacks around the move constructor.

class MessageClient : public std::enable_shared_from_this<MessageClient> {
private:
    boost::asio::io_context io_context;

    void send() {
      // code
    }

    void operator() () {
      // code
    }
};

int main () {
   MessageClient client;
   auto pclient = client.shared_from_this();
   std::thread thread(std::move(client));

   pclient->send(); // terminate called after throwing an instance of  'std::bad_weak_ptr'
                    // what():  bad_weak_ptr
                    // Aborted (core dumped)
   thread.join();
}

EDIT

I got my answer. I understand now that I have used the enable_shared_from_this incorrectly, but real answer is, that there is no way of solving the issue which does not involve wrapping the object into another object, such as smart pointer or lambda function (which is wrapping the object into a functor). Personally I have found the second solution simpler, that is why I have selected it.

MessageClient client;
std::thread thread([&client](){client.run();});

client.send();

EDIT2

I have found a more obvious solution. If I create a reference from the object I do not have to wrap it:

MessageClient client;
std::thread thread(std::ref(client));

client.send();
  • 1
    shared_from_this can be called only inside member function of MessageClient when there is at least one instance of shared_ptr which manges it. – rafix07 Jun 7 at 9:59
1

Deriving from enable_shared_from_this hints that every instance is owned by some shared_ptrs. Your problem is that client isn't, and is unrelated to moving it into the thread.

You have undefined behaviour on this line:

auto pclient = client.shared_from_this();

Just use a std::shared_ptr<MessageClient> from the start.

class MessageClient {
private:
    boost::asio::io_context io_context;

    void send() {
      // code
    }

    void operator() () {
      // code
    }
};

int main () {
   auto pclient = std::make_shared<MessageClient>();
   std::thread thread([pclient]() { (*pclient)(); });

   pclient->send(); 

   thread.join();
}
  • I do not understand this answer. What does shared_from_this exactly mean? In my understanding it should mean that even if the instance goes out of scope, the shared pointer derived from it should remain valid. – user1396055 Jun 7 at 11:20
  • client is not managed by a shared pointer, calling shared_from_this on it has undefined behaviour. In C++17 it becomes defined as throwing. You can't magic shared ownership of an object with automatic storage duration. – Caleth Jun 7 at 11:23
  • what does enable_shared_from_this do? – user1396055 Jun 7 at 11:29
  • It allows you to get a shared_ptr that shares ownership with other existing shared_ptrs, from a method on the pointed-to object – Caleth Jun 7 at 11:30
  • does the shared pointer prevent the instance to be destroyed? if not then how is it different from simply taking this – user1396055 Jun 7 at 11:32
1

In main you could create two instances of shared_ptr which shares the same MessageClient object. One shared ptr can be moved into the body of thread, another stays in main and you can use it to communicate with the thread:

int main () 
{
   std::shared_ptr<MessageClient> client = std::make_shared<MessageClient>();
   std::shared_ptr<MessageClient> pclient = client;

   std::thread thread(
        [client = std::move(client)]()
        {
           (*client)(); // invoke body of thread
        });

   pclient->send(); // works fine
   thread.join();
}

demo


Your code with shared_from_this doesn't work because shared_from_this can be called only inside member function of MessageClient when you are sure that there is at least one instance of shared_ptr which manages this.

  • At the point where I create pclient, the client instance is valid. – user1396055 Jun 7 at 11:27
  • @user1396055 See reference about shared_from_this. In your case client is LOCAL VARIABLE. You can call shared_from_this only if there is shared_ptr which manages it. See examples at the link I attached. shared_from_this is searching control block to find smart pointer which refers to this, then increase its reference counter. In your case there is nothing to find, because no shared ptr pointing this exists. – rafix07 Jun 7 at 11:30
  • I got it now, it is much less useful than I thought – user1396055 Jun 7 at 11:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.