4.3. 连接 Connections
函数可以通过由 boost::signal
所提供的 connect()
和 disconnect()
方法的帮助来进行管理。 由于 connect()
会返回一个类型为 boost::signals::connection
的值,它们可以通过其它方法来管理。
- #include <boost/signal.hpp>
- #include <iostream>
- void func()
- {
- std::cout << "Hello, world!" << std::endl;
- }
- int main()
- {
- boost::signal<void ()> s;
- boost::signals::connection c = s.connect(func);
- s();
- c.disconnect();
- }
boost::signal
的 disconnect()
方法需要传入一个函数指针,而直接调用 boost::signals::connection
对象上的 disconnect()
方法则略去该参数。
除了 disconnect()
方法之外,boost::signals::connection
还提供了其它方法,如 block()
和 unblock()
。
- #include <boost/signal.hpp>
- #include <iostream>
- void func()
- {
- std::cout << "Hello, world!" << std::endl;
- }
- int main()
- {
- boost::signal<void ()> s;
- boost::signals::connection c = s.connect(func);
- c.block();
- s();
- c.unblock();
- s();
- }
以上程序只会执行一次 func()
。 虽然信号 s 被触发了两次,但是在第一次触发时 func()
不会被调用,因为连接 c 实际上已经被 block()
调用所阻塞。 由于在第二次触发之前调用了 unblock()
,所以之后 func()
被正确地执行。
除了 boost::signals::connection
以外,还有一个名为 boost::signals::scoped_connection
的类,它会在析构时自动释放连接。
- #include <boost/signal.hpp>
- #include <iostream>
- void func()
- {
- std::cout << "Hello, world!" << std::endl;
- }
- int main()
- {
- boost::signal<void ()> s;
- {
- boost::signals::scoped_connection c = s.connect(func);
- }
- s();
- }
因为连接对象 c 在信号触发之前被销毁,所以 func()
不会被调用。
boost::signals::scoped_connection
实际上是派生自 boost::signals::connection
的,所以它提供了相同的方法。它们之间的区别仅在于,在析构 boost::signals::scoped_connection
时,连接会自动释放。
虽然 boost::signals::scoped_connection
的确令自动释放连接更为容易,但是该类型的对象仍需要管理。 如果在其它情形下连接也可以被自动释放,而且不需要管理这些对象的话,就更好了。
- #include <boost/signal.hpp>
- #include <boost/bind.hpp>
- #include <iostream>
- #include <memory>
- class world
- {
- public:
- void hello() const
- {
- std::cout << "Hello, world!" << std::endl;
- }
- };
- int main()
- {
- boost::signal<void ()> s;
- {
- std::auto_ptr<world> w(new world());
- s.connect(boost::bind(&world::hello, w.get()));
- }
- std::cout << s.num_slots() << std::endl;
- s();
- }
以上程序使用 Boost.Bind 将一个对象的方法关联至一个信号。 在信号触发之前,这个对象就被销毁了,这会产生问题。 我们不传递实际的对象 w,而只传递一个指针给 boost::bind()
。 在 s()
被实际调用的时候,该指针所引向的对象已不再存在。
可以如下修改这个程序,使得一旦对象 w 被销毁,连接就会自动释放。
- #include <boost/signal.hpp>
- #include <boost/bind.hpp>
- #include <iostream>
- #include <memory>
- class world :
- public boost::signals::trackable
- {
- public:
- void hello() const
- {
- std::cout << "Hello, world!" << std::endl;
- }
- };
- int main()
- {
- boost::signal<void ()> s;
- {
- std::auto_ptr<world> w(new world());
- s.connect(boost::bind(&world::hello, w.get()));
- }
- std::cout << s.num_slots() << std::endl;
- s();
- }
如果现在再执行,num_slots()
会返回 0
以确保不会试图调用已销毁对象之上的方法。 仅需的修改是让 world
类继承自 boost::signals::trackable
。 当使用对象的指针而不是对象的副本来关联函数至信号时,boost::signals::trackable
可以显著简化连接的管理。