【问题标题】:does the move constructor invalidate shared_from_this移动构造函数是否使 shared_from_this 无效
【发布时间】:2019-06-07 07:09:53
【问题描述】:

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

移动构造函数是否使共享指针无效?如果是这样,那么优雅的 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();

EDIT2

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

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

client.send();

【问题讨论】:

  • shared_from_this 只能在 MessageClient 的成员函数内部调用,前提是至少有一个 shared_ptr 实例对其进行管理。

标签: c++ multithreading shared-ptr move-constructor enable-shared-from-this


【解决方案1】:

派生自enable_shared_from_this 暗示每个 实例都归某些shared_ptrs 所有。您的问题是 client 不是,并且与将其移入线程无关。

您在这一行有未定义的行为:

auto pclient = client.shared_from_this();

从一开始就使用std::shared_ptr&lt;MessageClient&gt;

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

【讨论】:

  • 我不明白这个答案。 shared_from_this 到底是什么意思?在我的理解中,这应该意味着即使实例超出范围,从它派生的共享指针也应该保持有效。
  • 客户端不是由共享指针管理的,在它上面调用 shared_from_this 有未定义的行为。在 C++17 中,它被定义为抛出。您不能使用自动存储持续时间来魔术共享对象的所有权。
  • enable_shared_from_this 有什么作用?
  • 它允许您从指向对象的方法中获取与其他现有shared_ptrs 共享所有权的shared_ptr
  • 共享指针是否防止实例被销毁?如果不是,那么它与简单地接受this 有何不同
【解决方案2】:

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

demo


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

【讨论】:

  • 在我创建 pclient 时,客户端实例是有效的。
  • @user1396055 见reference about shared_from_this。在您的情况下,客户端是本地变量。仅当存在管理它的 shared_ptr 时,您才能调用 shared_from_this。请参阅我附加的链接中的示例。 shared_from_this 正在搜索 控制块 以找到引用 this 的智能指针,然后增加其引用计数器。在您的情况下,找不到任何东西,因为不存在指向 this 的共享 ptr。
  • 我现在知道了,它没有我想象的那么有用
猜你喜欢
  • 1970-01-01
  • 2014-11-08
  • 2011-03-24
  • 2012-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多