升压信号2将插槽传递到成员功能以断开连接

Boost Signals2 pass Slot to member Function for Disconnecting

本文关键字:成员 功能 连接 断开 信号 插槽      更新时间:2023-10-16

我有以下使用简单boost::Signals2::Signal的类:

class Button {
using OnClick = signal<void()>;
public:
using OnClickSlotType = OnClick::slot_type;
boost::signals2::connection add_handler(const OnClickSlotType& slot) {
return click.connect(slot);
}
void remove_handler(const OnClickSlotType& slot) {
std::cout << "Disconnectn";
click.disconnect(&slot);
}
signal<void()> click;
};

我使用如下所示的类:

void demo() { std::cout << "Demo calledn"; }
void second() { std::cout << "Secondn"; }
int main() {
Button btn;
btn.add_handler(&demo);
btn.add_handler(&second);
btn.click();
btn.remove_handler(&demo);
btn.click();
}

但功能demo并未断开连接。输出始终为:

Demo called
Second
Disconnect
Demo called
Second

如何正确断开功能与信号的连接?

您可以多次注册同一函数,从而导致多个连接。

因此,该函数的标识不足。

相反,您可以使用connection对象断开特定连接:

住在科里鲁

auto d = btn.add_handler(&demo);
btn.add_handler(&second);
btn.click();
d.disconnect();
btn.click();

指纹

Demo called
Second
Disconnect doesn't require access to either source or subscriber
Second

这样做的美妙之处在于它将来源、订阅者和连接分离。您可以有一个连接表并断开它们,而无需知道所涉及的各方。

奖励:scoped_connection

作用域连接是连接的 RAII 包装器。这意味着您可以以与包装器的生命周期相关联的异常安全方式断开连接。这对于防止终身问题非常有用:

住在科里鲁

#include <boost/signals2/signal.hpp>
#include <iostream>
#include <optional>
using boost::signals2::signal;
class Button {
using OnClick = signal<void(std::string const&)>;
public:
using OnClickSlotType = OnClick::slot_type;
boost::signals2::connection add_handler(const OnClickSlotType& slot) {
return click.connect(slot);
}
OnClick click;
};
struct Demo {
Demo(Button& btn, std::string name)
: _connection(btn.add_handler(std::ref(*this))),
_name(std::move(name))
{ }
Demo(Demo const&) = delete;
Demo(Demo&&) = delete;
void operator()(std::string const& msg) const {
std::cout << _name << " called (" << msg << ")n";
}
private:
boost::signals2::scoped_connection _connection;
std::string _name;
};
int main() {
Button btn;
std::optional<Demo> foo;
{
Demo bar(btn, "bar");
btn.click("first click L:" + std::to_string(__LINE__));
foo.emplace(btn, "foo");
btn.click("second click L:" + std::to_string(__LINE__));
foo.reset();
btn.click("third click L:" + std::to_string(__LINE__));
} // bar is disconnecteded
// no connections left
btn.click("last click L:" + std::to_string(__LINE__));
}

指纹

bar called (first click L:42)
bar called (second click L:46)
foo called (second click L:46)
bar called (third click L:50)