使用 boost::signals2::scoped_connection 对象作为 class 的成员来实现自动连接生命周期是否安全?

Is it safe to use a boost::signals2::scoped_connection object as member of a class for automatic connection lifetime?

关于信号可能由不同线程触发这一事实,我想知道以下代码是否安全:

using IntSignal = boost::signals2::signal<void(int)>;

class Foo
{
public:

  Foo(IntSignal& signal)
    : some_resource(new int(0))
  {
    scoped_connection = signal.connect([this](int i) { some_action(i); });
  }

  ~Foo()
  {
    delete some_resource;
  }

private:

  void some_action(int i)
  {
    *some_resource = i;
  }

  int* some_resource;

  boost::signals2::scoped_connection scoped_connection;
}

编辑:为 some_action 添加了一个虚构的资源、析构函数和一个实现,以使其更加清晰。带着这个问题,我想澄清一下我的假设是否正确,即信号槽可能在 Foo 的析构函数之后但在 scoped_connection 的析构函数之前被调用。为简洁起见,我省略了保护 some_resource 的互斥量,但是,它与问题无关。

虽然 Foo 实例被销毁时连接会被断开,但 Foo 自己的析构函数调用和 Foo 的析构函数调用之间可能存在微小的差距成员。如果资源在 some_action 内被销毁后仍在使用,这可能会更成问题。

我应该使用普通连接并在 Foo 的析构函数中断开它们吗?将 scoped_connection 成员作为 class 的最后一个成员(应该首先销毁)并省略任何销毁逻辑是否安全?

你是对的,如果在信号为 运行 并访问 some_resource.

时调用 Foo 的析构函数,则可能存在竞争

一个安全的解决方案是在插槽为 运行:

时延长 Foo 的使用寿命
class Foo : public std::enable_shared_from_this<Foo>
{
public:

  Foo(IntSignal& signal)
    : some_resource(new int(0))
  {        
      // moved connection initialization to a method since weak_from_this will  
      // be empty inside the constructor. It is initialized only afterwards.
      // It also make sense to connect your signal only after object
      // is fully initialized
  }

  void InitConnection()
  {
     auto weak_self = weak_from_this(); 
     scoped_connection = signal.connect(
       [weak_self](int i) 
      { 
         if (auto self = weak_self.lock())
         {
            // we managed to promote weak_self to a shared_ptr, 'this' will be alive 
            // as long as this scope lives
            some_action(i); // safe
         }
      });

  }

  ~Foo()
  {
     // will only be invoked after Foo's reference count drops to zero.
     // not during the signal is emitted
     delete some_resource; 
  }

private:    
  void some_action(int i)
  {
    *some_resource = i;
  }

  int* some_resource;    
  boost::signals2::scoped_connection scoped_connection;
}

备注:

  1. enable_shared_from_thisweak_ptr 初始化为 'this'。对于您描述的情况,这是一个很好的工具。查看更多 here.
  2. 确保将 Foo 创建为 shared_ptr,否则 weak_from_this 将无法工作。 请记住:Foo 在 2 个线程之间共享