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 オブジェクトはスコープから外れることはなく、削除されることのないオブジェクトへの shared_ptr を保持します。
これを回避するには、shared_ptr の代わりに this ポインターを使用してバインドし、メンバー shared_ptr を使用してオブジェクトを存続させてから、ハンドラー関数で解放しますが、設計が少し複雑すぎるように感じます。切断時にsignals2に強制的にスロットを削除させる方法はありますか? または、デザインを簡素化するために他にできることはありますか?
どんなコメントでも大歓迎です!