[Smart Ptr][Bind] Implementaion of Weak Callback Function "weak_fn"

Hello, Today boost::bind allows to use shared_ptr to ensure that when the function is called the object exists: shared_ptr<bar> bar_ptr; function<void()> foo; foo=bind(&bar::slot,bar_ptr) Now even if we call bar_ptr.reset() the object is still owned by foo. But in some cases this is not good enough. This may create cyclic dependecies if A has shared_ptr to B and gives it a callback to A cyclic dependecy is created, so sometimes it would be useful to be able to provide weak bind function that is called iff the object exists -- that uses weak_ptr insteas of shared one. I has written a small draft of boost::weak_fn template<T> boost::weak_fn(void (T::*p)(...), weak_ptr<T> ptr) That creates such callback, it can be used with boost::bind similary to mem_fn: class foo { void bar(int x); }; Like: function<void(int x,int y)> f2=bind(weak_fn(&foo::bar,bar_ptr),_1+_2); function<void(int x)> f1=weak_fn(&foo::bar,bar_ptr); function<void()> f1=bind(weak_fn(&foo::bar,bar_ptr),0); The code availible from: http://art-blog.no-ip.info/files/weak_fn.tar.gz It is very initial implementation that gives functions from 0 to 3 parameters. - I just want to be sure if this is correct direction? - Comments on implementaions? Can it be done better? - Do I miss something? Thanks, Artyom

Artyom <artyomtnk <at> yahoo.com> writes:
Hello,
Today boost::bind allows to use shared_ptr to ensure that when the function is called the object exists:
shared_ptr<bar> bar_ptr; function<void()> foo;
foo=bind(&bar::slot,bar_ptr)
Now even if we call bar_ptr.reset() the object is still owned by foo. But in some cases this is not good enough. This may create cyclic dependecies if A has shared_ptr to B and gives it a callback to A cyclic dependecy is created, so sometimes it would be useful to be able to provide weak bind function that is called iff the object exists -- that uses weak_ptr insteas of shared one.
<snip> I can't comment on whether the direction is correct, but would be in support of such a capability having recently run into the same need. However, I seem to recall something like this coming up before and the rationale for not supporting it is was that the behavior to follow when the weak pointer is expired is subjective. That is, in some cases you may want an exception, and in other you may want nothing to happen. -Brian

On Sat, Mar 21, 2009 at 2:39 PM, bnv <bnv@nc.rr.com> wrote:
Artyom <artyomtnk <at> yahoo.com> writes:
Hello,
Today boost::bind allows to use shared_ptr to ensure that when the function is called the object exists:
shared_ptr<bar> bar_ptr; function<void()> foo;
foo=bind(&bar::slot,bar_ptr)
Now even if we call bar_ptr.reset() the object is still owned by foo.
However, I seem to recall something like this coming up before and the rationale for not supporting it is was that the behavior to follow when the weak pointer is expired is subjective. That is, in some cases you may want an exception, and in other you may want nothing to happen.
I tried doing what my intuition told me would be the moral equivalent, which would be to use composition to give bind a weak_ptr instead of a smart one: foo = bind( &bar::slot, bind( &weak_ptr<bar>::lock, weak_ptr<bar>( bar_ptr ) ) ); However, one of those binds must be persisting the smart pointer somewhere, because calling foo always has an effect for me, where I would expect it to segfault after the shared_ptr is reset, since lock() would return a null shared_ptr. You might be able to see the problem though, and get where you want to be. HTH, Christopher

bnv wrote:
I can't comment on whether the direction is correct, but would be in support of such a capability having recently run into the same need.
Me too.
However, I seem to recall something like this coming up before and the rationale for not supporting it is was that the behavior to follow when the weak pointer is expired is subjective. That is, in some cases you may want an exception, and in other you may want nothing to happen.
I think, it should be possible to create a policy-based solution. Something like this: weak_ptr< A > p; bind(&A::foo, throw_if_invalid(p)); bind(&A::foo, ignore_if_invalid(p)); bind(&A::foo, call_if_invalid(p, bar)); // bar is a function object This is possible if throw_if_invalid, etc. return some proxy object which has an overloaded get_pointer function and operator->* that does the job. template< typename T, typename FallbackFunT, typename FunT > class weak_ptr_caller { weak_ptr< T > const& m_p; FallbackFunT const& m_fallback; FunT m_fun; public: explicit weak_ptr_caller( weak_ptr< T > const& p, FallbackFunT const& fb, FunT f) : m_p(p), m_fallback(fb), m_fun(f) {} // here goes a bunch of operator() overloads ... operator() (args) const { if (shared_ptr< T > p = m_p.lock()) return (get_pointer(p)->*m_fun)(args); else return m_fallback(); } }; template< typename T, typename FunT > class weak_ptr_proxy { weak_ptr< T > m_p; FunT m_fun; public: explicit weak_ptr_proxy(weak_ptr< T > p, FunT f) : m_p(p), m_fun(f) {} template< typename F > weak_ptr_caller< T, Fun, F > operator->*(F f) const { return weak_ptr_caller< T, Fun, F >(m_p, m_fun, f); } }; template< typename T, typename FunT > weak_ptr_proxy< T, FunT >& get_pointer(weak_ptr_proxy< T, FunT >& p) { return p; } template< typename T, typename FunT > weak_ptr_proxy< T, FunT > call_if_invalid(weak_ptr< T > p, FunT f) { return weak_ptr_proxy< T, FunT >(p, f); }
participants (4)
-
Andrey Semashev
-
Artyom
-
bnv
-
Christopher Currie