1

我想用一个包含不可复制成员的类开始一个线程。为了与线程通信,我想在将对象移入线程之前从对象创建一个共享指针。

移动构造函数是否使共享指针无效?如果是这样,那么优雅的 C++ 方法是什么?一种解决方案是将 MessageClient 包装到共享指针中,但这会绕过移动构造函数。

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();
}

编辑

我得到了我的答案。我现在明白我使用的enable_shared_from_this不正确,但真正的答案是,没有办法解决不涉及将对象包装到另一个对象中的问题,例如智能指针或 lambda 函数(将对象包装到函子)。我个人发现第二种解决方案更简单,这就是我选择它的原因。

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

client.send();

编辑2

我找到了一个更明显的解决方案。如果我从对象创建引用,则不必包装它:

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

client.send();
4

2 回答 2

1

main您可以创建两个shared_ptr共享相同MessageClient对象的实例。一个共享 ptr 可以移动到线程主体中,另一个保留在 main 中,您可以使用它与线程通信:

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();
}

演示


您的代码shared_from_this不起作用,因为shared_from_this只能在MessageClient您确定至少有一个实例的成员函数内部调用shared_ptrmanages this

于 2019-06-07T10:12:58.677 回答
1

源自每个实例都由某些s拥有的enable_shared_from_this提示。您的问题不是,并且与将其移入线程无关。shared_ptrclient

您在此行有未定义的行为:

auto pclient = client.shared_from_this();

从一开始就使用 a std::shared_ptr<MessageClient>

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();
}
于 2019-06-07T10:43:24.407 回答