Удаление силы слота в повышении:: signals2

Я нашел что повышение:: signals2 использует вид ленивого удаления связанных слотов, которое мешает использовать соединения в качестве чего-то, что управляет временем жизни объектов. Я ищу способ вынудить слоты быть удаленными непосредственно при разъединении. Любые идеи о том, как работать вокруг проблемы путем разработки моего кода по-другому, также ценятся!

Это - мой сценарий: у Меня есть класс Команды, ответственный за то, что сделал что-то, что занимает время асинхронно, выглядя примерно так (упрощенный):

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.

класс Команды поддерживает себя путем получения shared_ptr к себе, который связывается с сигналом ActualWorker с помощью повышения:: связать.

Когда рабочий завершается, обработчик в Команде вызывается. Теперь, так как я хотел бы, чтобы Объект команды был уничтожен, я разъединяюсь от сигнала как видно в коде выше. Проблема состоит в том, что фактический объект слота не удален при разъединении он только отмечен как недопустимый и затем удаленный в более позднее время. Это в свою очередь, кажется, зависит от сигнала стрелять снова, который он не делает в моем случае, ведя к слоту, никогда не истекающему. Повышение:: свяжите объект, таким образом никогда не выходит из объема, содержа shared_ptr к моему объекту, который никогда не будет удаляться.

Я могу работать вокруг этого путем привязки использования этого указателя вместо shared_ptr и затем хранения моего объектного живого использования участника shared_ptr, который я затем выпускаю в функции-обработчике, но это отчасти заставляет дизайн чувствовать себя немного сверхсложным. Существует ли способ вынудить signals2 удалить слот при разъединении? Или есть ли что-то еще, что я мог сделать для упрощения дизайна?

Любые комментарии ценятся!

12
задан villintehaspam 14 January 2010 в 19:47
поделиться

3 ответа

Являются поведением, еще строгим с scoped_connection?

Так, а не:

void Execute() {
    m_WorkerConnection = m_MyWorker.OnWorkDone.connect(boost::bind
        (&Command::Handle_OnWorkComplete, shared_from_this());

    // launch asynchronous work here and return
}

...

boost::signals2::connection m_WorkerConnection;

Вместо этого использование:

void Execute() {
    boost::signals2::scoped_connection m_WorkerConnection
        (m_MyWorker.OnWorkDone.connect(boost::bind
        (&Command::Handle_OnWorkComplete, shared_from_this()));

    // launch asynchronous work here and return
}   // connection falls out of scope

(построенный из копии из повышение:: signals2:: связь )

я не использовал вида передачи сигналов, таким образом, это - больше предположения, чем что-либо еще, но после Выполняет () , вам не было бы нужно к разъединение () , так как scoped_connection обращается с ним для вас. Это скорее «упрощение дизайна,» чем решение вашей проблемы. Но это может означать, что можно Выполнить () , а затем немедленно ~ Команда () (или удалить shared_ptr).

Надеюсь, что это поможет.

EDIT: И с помощью Execute () , затем немедленно ~ Command () Я, очевидно, имею в виду вне вашего объекта Command. Когда вы создаете команду для ее выполнения, вы должны иметь возможность сказать:

cmd->Execute();
delete cmd;

Или подобное.

1
ответ дан 2 December 2019 в 22:38
поделиться

boost::signals2 действительно очищает слоты во время connect/invoke.

Так что если все слоты отсоединятся от сигнала, вызов сигнала во второй раз ничего не вызовет, но должен очистить слоты.

Отвечая на ваш комментарий, да, повторный вызов сигнала небезопасен, если есть другие подключенные слоты, так как они будут вызваны снова. В этом случае я предлагаю вам пойти другим путем и подключить фиктивный слот, а затем отключить его, когда будет вызван ваш "настоящий" слот. Подключение другого слота очистит устаревшие соединения, поэтому ваш слот должен быть освобожден.

Только убедитесь, что вы не храните в фиктивном слоте ссылки, которые нужно освободить, иначе вы вернетесь к тому, с чего начали.

4
ответ дан 2 December 2019 в 22:38
поделиться

Это невероятно раздражающий аспект boost :: signal2.

Подход, который я использовал для решения этой проблемы, заключается в том, чтобы сохранить сигнал в scoped_ptr, и когда я хочу принудительно отключить все слоты, я удаляю сигнал. Это работает только в тех случаях, когда вы хотите принудительно отключить все соединения с сигналом.

2
ответ дан 2 December 2019 в 22:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: