Boost logo

Boost Users :

From: Nat Goodspeed (nat_at_[hidden])
Date: 2007-10-27 18:20:21


I have a callback design based around Boost.Signals. The documentation says:

http://boost.org/doc/html/signals/tutorial.html#id1627926

"Warning: User-defined function objects and function objects from other
libraries (e.g., Boost.Function or Boost.Lambda) do not implement the
required interfaces for trackable object detection, and will silently
ignore any bound trackable objects. Future versions of the Boost
libraries will address this limitation."

I would like to define a filter function object to be used something
like this:

// define signal_t, handler_t
typedef boost::signal<void()> signal_t;
typedef signal_t::slot_type handler_t;

signal_t mySignal;

// straightforward use case
struct Listener: public boost::signals::trackable
{
     void someMethod() {}
};
Listener* myListener = new Listener();
mySignal.connect(boost::bind(&Listener::someMethod, myListener));
// the following should disconnect
delete myListener;
mySignal(); // should do nothing

// define filter function object
struct Filter
{
     Filter(const handler_t& handler, somedata_t somedata):
         mHandler(handler),
         mSomeData(somedata) {}
     void operator()()
     {
         if (mSomeData)
         {
             mHandler();
         }
     }
     handler_t mHandler;
     somedata_t mSomeData;
};

// use filter function object
myListener = new Listener();
mySignal.connect(Filter(boost::bind(&Listener::someMethod, myListener),
                         somedata));
// doc promises the following will NOT disconnect
delete myListener;
mySignal(); // the dreaded undefined behavior

Unfortunately there are two hurdles to getting there.

1. How could I code Filter to honor the 'trackability' of the passed-in
handler?

2. slot_type is not itself callable: mHandler() doesn't work.

2a. I could use boost::function for handler_t instead:
typedef boost::function<void()> handler_t;
but the documentation promises that this, too, will ignore Filter's
trackable base class.

2b. I could make Filter store a signal_t instead of a handler_t.
Filter's constructor could call mHandler.connect(handler) instead of
initializing mHandler from handler. But that doesn't work because
signal_t is noncopyable, and passing a Filter instance to connect()
copies it.

I'd be willing to make Filter trackable, stipulating that Filter
instances must live on the heap:

mySignal.connect(new Filter(etc.)); // or boost::bind() of same

Then Filter could store signal_t because the Filter object wouldn't be
copied. When the Listener object is destroyed, it would automatically
disconnect from the Filter's signal_t. But that would leave me with an
orphan Filter object with an empty signal_t permanently connected to
mySignal.

Could Filter be informed when slots are disconnected from its contained
signal_t? When the last slot is disconnected, it could 'delete this'.
With Filter trackable, that would disconnect it from mySignal, and
everyone would be happy.

(There's the performance cost of introducing another signal object
through which the call must be forwarded, but I hope that will be
negligible.)

So: is there any way for Filter to intercept control when the last
(only) slot disconnects from Filter::mHandler? (Filter stores a subclass
of signal_t?)

Is there any other way to accomplish what I'm trying to do here?

Thanks.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net