我发现 boost::signals2 使用了一种对连接槽的延迟删除,这使得很难将连接用作管理对象生命周期的东西。我正在寻找一种方法来强制在断开连接时直接删除插槽。任何关于如何通过不同地设计我的代码来解决问题的想法也值得赞赏!
这是我的场景:我有一个 Command 类负责异步执行需要时间的操作,看起来像这样(简化):
class ActualWorker {
public:
boost::signals2<void ()> OnWorkComplete;
};
class Command : boost::enable_shared_from_this<Command> {
public:
...
void Execute() {
m_WorkerConnection = m_MyWorker.OnWorkDone.connect(boost::bind(&Command::Handle_OnWorkComplete, shared_from_this());
// launch asynchronous work here and return
}
boost::signals2<void ()> OnComplete;
private:
void Handle_OnWorkComplete() {
// get a shared_ptr to ourselves to make sure that we live through
// this function but don't keep ourselves alive if an exception occurs.
shared_ptr<Command> me = shared_from_this();
// Disconnect from the signal, ideally deleting the slot object
m_WorkerConnection.disconnect();
OnComplete();
// the shared_ptr now goes out of scope, ideally deleting this
}
ActualWorker m_MyWorker;
boost::signals2::connection m_WorkerConnection;
};
该类的调用方式如下:
...
boost::shared_ptr<Command> cmd(new Command);
cmd->OnComplete.connect( foo );
cmd->Execute();
// now go do something else, forget all about the cmd variable etcetera.
Command 类通过使用 boost::bind 将 shared_ptr 绑定到 ActualWorker 信号来使自己保持活动状态。
当工作人员完成时,将调用 Command 中的处理程序。现在,由于我希望销毁 Command 对象,因此我断开了与信号的连接,如上面的代码所示。问题是实际的槽对象在断开连接时并没有被删除,它只是被标记为无效,然后在以后删除。这反过来似乎取决于再次触发的信号,在我的情况下它没有这样做,导致插槽永不过期。boost::bind 对象因此永远不会超出范围,将 shared_ptr 保存到我的对象中,该对象永远不会被删除。
我可以通过使用 this 指针而不是 shared_ptr 进行绑定来解决此问题,然后使用成员 shared_ptr 保持我的对象处于活动状态,然后我在处理程序函数中释放该成员,但这有点让设计感觉有点过于复杂。有没有办法在断开连接时强制信号2删除插槽?或者我还能做些什么来简化设计?
任何意见表示赞赏!