Boost logo

Boost Users :

Subject: Re: [Boost-users] [signals2][review] The review of the signals2 library (formerly thread_safe_signals) begins today, Nov 1st
From: Nat Goodspeed (nat_at_[hidden])
Date: 2009-02-17 17:36:52


Frank Mori Hess wrote:

>> 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.
>
> 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.

Thanks for the suggestion! I'm excited about this approach, but I've run
into a snag.

As you note above, in addition to the case of my own Trackable base
class, I want my visitor to detect a bound boost::shared_ptr<anything>
and pass the shared_ptr to my new slot_type object's track() method. In
fact, for a boost::shared_ptr<SomeTrackableSubclass>, I want the
shared_ptr tracking to take precedence. As you said, this is the safer
mechanism.

I can in fact detect a bound shared_ptr and pass it to track() as I
want. The problem is that binding a shared_ptr captures a copy, so the
referenced object will live until the connection is explicitly
disconnected! That makes the slot_type::track() mechanism moot.

It looks as though I could only achieve what I want if my visit_each()
visitor could *modify* the boost::bind object to replace the bound
shared_ptr with its wrapped plain pointer. I don't believe this is possible?

(Aside: I tried extending my visitor's detection to boost::weak_ptr,
changing my test code by explicitly converting my shared_ptr to weak_ptr
before passing it to boost::bind(). I couldn't instantiate
slot_type(boost::bind(...boost::weak_ptr<anything>...)) until I
specialized boost::get_pointer() myself. (I'm using Boost 1.34.1
augmented with the Signals2 library.) In any case, though, requiring
coders to remember to explicitly wrap any boost::smart_ptr instance in
boost::weak_ptr feels like the wrong solution.)

Perhaps I could build a sufficiently smart boost::visit_each() visitor
to reconstruct the original boost::bind() expression, but substituting a
plain pointer for any smart_ptr? I'm not confident I can do that without
relying on too many boost::bind implementation details.

I'm hoping one of you will suggest a better approach. :-)

> 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.

Thanks for the warning. I'd prefer to handle bound shared_ptrs, if I can
do so without making the referenced objects immortal.


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