
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Wednesday 11 February 2009 15:08 pm, Nat Goodspeed wrote:
Frank Mori Hess wrote:
I have added a thread-UNsafe boost::signals2::trackable to svn to ease porting of single-threaded Boost.Signals code that doesn't need to be made thread-safe.
That will be useful transitionally if we can count on a thread-safe boost::signals2::trackable arriving later. If signals2::trackable would only ever be thread-unsafe, it's not useful to us.
It's intended for people who don't want to bother rewriting a lot of Boost.Signals code that doesn't need thread-safety.
With an instance 'smartptr' of ListenerClass derived from boost::trackable, I'd like to write something like:
holler.listen(boost::bind(&ListenerClass::method, smartptr, _1));
If my listen() method were able to tease apart the object returned from bind(), it could detect the case of a shared_ptr<boost::trackable subclass>.
It could, by using boost::visit_each. boost::bind supports visit_each to let you apply a visitor to all the objects bound inside the returned functor. The signals libraries use visit_each to discover trackable objects that have been bound into slots.
Since I don't know how to do that, I've introduced a number of alternative ways to get disconnect-on-destruction. I don't yet know which, if any of them, will become the prevalent idiom. None is as easy/foolproof as boost::trackable, since each requires the caller to explicitly request connection management.
Maybe I'm overlooking something that would make my life much easier -- suggestions welcome!
I would spend some time learning how to use visit_each with bind. You could implement a wrapper function that inspects slots for your own Trackable base class objects, and then takes whatever step is needed to extract a shared_ptr and pass it to slot::track before connecting.
2. For transient objects not managed by shared_ptr, I've also introduced a Trackable base class containing boost::ptr_vector<boost::signals2::scoped_connection> mConnections;
The Trackable::track(const connection& c) method does this: mConnections.push_back(new scoped_connection(c));
So destroying a Trackable subclass object disconnects any connections passed to track().
Just a note: you need to be careful about connecting these transient objects, since the signal can't employ shared_ptr to prevent them from destructing in mid-signal invocation.
3. One of my colleagues has a class that (with my changes) now also wraps a boost::signals2::signal. He strongly dislikes the variation between my listen(const slot_type&) and listen(method ptr, shared_ptr) methods, so he's changed his own connectFor() method as follows:
template <typename POINTER> connection connectFor(const slot_type& slot, const POINTER& ptr) { connection c(mSignal.connect(slot)); Trackable* isTrackable(dynamic_cast<Trackable*>(ptr)); if (isTrackable) { isTrackable->track(c); } return c; }
Again, with this usage the signal can't prevent destruction in mid-signal invocation.
A thread-safe boost::signals2::trackable mechanism would allow us to drop back to a single universal call:
holler.listen(boost::bind(&SomeClass::method, ptr, _1));
with connection management automatically engaged as appropriate.
You can implement this now, once you get some experience with visit_each. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFJk0CD5vihyNWuA4URAoyIAJ9u1cmheH4+MQx9hhLIZzGg41+x2gCg3Bat 24TIJ9OQCAAyQUXdr+90sqo= =JPSL -----END PGP SIGNATURE-----