Я обнаружил, что 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 сохраняет себя в живых, получая shared_ptr для себя, который привязан к сигналу ActualWorker с использованием boost:: bind.
Когда рабочий завершается, вызывается обработчик в команде. Теперь, поскольку я хотел бы, чтобы объект Command был уничтожен, я отсоединяюсь от сигнала, как это видно из кода выше. Проблема в том, что фактический объект слота не удаляется при отключении, он помечен как недействительный, а затем удален позже. Это, в свою очередь, зависеть от сигнала, чтобы он снова срабатывал, чего он не делает в моем случае, что приводит к тому, что слот никогда не истекает. Таким образом, объект boost:: bind никогда не выходит за пределы области видимости, сохраняя shared_ptr для моего объекта, который никогда не будет удален.
Я могу обойти это, связываясь с помощью этого указателя вместо shared_ptr, а затем сохраняя свой объект живым, используя член shared_ptr, который затем я освобождаю в функции обработчика, но это немного заставляет дизайн чувствовать себя слишком сложным. Есть ли способ заставить сигналы2 удалить слот при отключении? Или я могу сделать что-то еще, чтобы упростить дизайн?
Любые комментарии оценены!