我发现 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 绑定到 ActualWorker 信号的 Shared_ptr 来保持自身的活动。
当工作程序完成时,将调用 Command 中的处理程序。现在,由于我希望销毁 Command 对象,因此我断开了与信号的连接,如上面的代码所示。问题是,实际的槽对象在断开连接时不会被删除,它只是被标记为无效,然后在稍后删除。这反过来似乎取决于再次触发的信号,但在我的情况下它不会这样做,导致插槽永远不会过期。因此 boost::bind 对象永远不会超出范围,将一个永远不会被删除的对象保存到我的对象中。
我可以通过使用 this 指针而不是共享指针进行绑定,然后使用成员共享指针使对象保持活动状态来解决此问题,然后在处理程序函数中释放该成员,但这会让设计感觉有点过于复杂。有没有办法强制 Signal2 在断开连接时删除插槽?或者我还可以做些什么来简化设计?
任何评论表示赞赏!