help boost::bind and shared pointers

Started by
11 comments, last by chairthrower 15 years, 11 months ago
I have this problem. Im using boost::bind for programming the call-back mechanism for a gui system and to pass messages (possibly, delayed messages). My problem is, that when i bind member functions, if i specify the instance of the class as a shared_ptr, then i get memory leaks because the binding's shared_ptr to the instance keeps it alive, and it potentially produces cyclic references that in the current model, would be complicated to break. And of course, if i use raw pointers to the binding instances, then i'll get a crash if the instance has been destroyed and i try to execute the binding function. So what i would need, is to use bind with weak pointers, and just do nothing if locking it fails. I'm not sure how to do that, or how to assemble a good walkaround. I'd like it to be as automatic as possible. Thanks for your time, i appreciate any help :)
http://www.teatromagico.net
Advertisement
Quote:So what i would need, is to use bind with weak pointers, and just do nothing if locking it fails.
Can't do it directly, unfortunately. This is something I've really wanted for boost::bind and boost::signal for awhile. There's half-decent reasons behind it (no always-applicable response for dead ptrs), but I think the main problem is that it doesn't fall cleanly on any one side of the bind/signal/smart_ptr trifurcation.

A workaround is to boost::bind to a static function which takes a weak_ptr, locks it, and calls the non-static version. Heck, you could wrap this up in some template functions without much trouble. There's also other event libraries out there which don't suffer from this limitation, because they implement their own weak_ptr-like things.
I don't think i could do the template wrap up you mention without breaking things. Im quite new to programming my own templates.

Someone at the boost maillist suggested me looking at the Thread Safe version of Signals. It seems you set up the signal to track the shared pointers, and automatically disconnects the ones that expire. I think i'll take a look at it.

But im still looking for more ideas, and thanks Sneftel for your time :).

PD: I'd appreciate some guidelines in case i decide to try to make the template wrapper you proposed.
http://www.teatromagico.net
Quote:Original post by ElPeque2
Someone at the boost maillist suggested me looking at the Thread Safe version of Signals. It seems you set up the signal to track the shared pointers, and automatically disconnects the ones that expire. I think i'll take a look at it.

That's the "trackable" thing. It works okay... but forces you to use raw, instead of shared, pointers. BTW, it's in main boost::signals; you don't need the thread safe version.

EDIT: Now that I look at it, thread-safe signals has discarded trackable in favor of weak_ptr. Awesome. Go with that.
What do you mean by "thread-safe signals has discarded trackable in favor of weak_ptr."

http://www.comedi.org/projects/thread_safe_signals/libs/thread_safe_signals/doc/html/signals/tutorial.html#id2566661

you mean this:

deliverNews.connect(signal_type::slot_type(&NewsMessageArea::displayNews,  newsMessageArea, _1).track(newsMessageArea));


is no longer necesary?
http://www.teatromagico.net
Oh, that's still necessary. What isn't necessary is making all your classes inherit from trackable, duplicating the ref-count stuff that shared_ptr already offers.
Oh, now i understad. I was not aware of that feature.

Great, thanks again for all your help :)
http://www.teatromagico.net
this is the wrapper code i use - i avoid an exposed global get() type function since the weakly bound object could go out of scope between the getting of the underlying pointer and the call of the bound function/method (fundamental difference with shared_ptr get() binding). here, at the time of the call a strong reference is used else an exception is thrown. its convenient since with a multicast delegate (bound multimethod? ) type thing since we can just iterate in a try block and remove 'dangling' type functions.

#include <iostream>#include <boost/shared_ptr.hpp>#include <boost/weak_ptr.hpp>#include <boost/function.hpp>#include <boost/bind.hpp>using namespace std;using namespace boost; class A{public:     A() {   }    virtual ~A() { }    void method( int value) { cout << "method() " << value << endl; }};  template< typename T >class from_weak_impl {public:    // result_type must defined and be const,     // we must return a strong ptr to prevent another thread unlocking between calls     typedef const shared_ptr< T> result_type;       weak_ptr< T> p;                                 inline from_weak_impl( const weak_ptr< T> &p0) : p( p0)  {   }    inline from_weak_impl( const shared_ptr< T> &p0) : p( p0)  {   }    inline result_type operator ()() const  {           // throws if bad...         return shared_ptr< T>( p);    }   };      template<class T>inline from_weak_impl< T> from_weak(  const weak_ptr<T> & p){        return from_weak_impl< T>( p);}   template<class T>inline from_weak_impl< T> from_weak(  const shared_ptr<T> & p){        return from_weak_impl< T>( p);}   int main(){    function< void( int) > f;    {    shared_ptr< A>  a( new A ) ;    shared_ptr< A>  sa = a;    weak_ptr< A>    wa = a;    f = bind( &A::method, sa,  _1  );                       // strong       f = bind( &A::method, bind( from_weak( wa)),  _1  );    // weak         f = bind( &A::method, bind( from_weak( sa)),  _1  );    // weak         }    // should throw since object a is out of scope    f( 123);}
It seems what you want is enable_shared_from_this.
See the shared_ptr documentation.
Quote:Original post by loufoque
It seems what you want is enable_shared_from_this.
How so?

This topic is closed to new replies.

Advertisement