|
Boost Users : |
From: Roman Perepelitsa (roman.perepelitsa_at_[hidden])
Date: 2008-05-15 03:43:34
Alejandro MartÃnez <elpeque2 <at> gmail.com> writes:
>
> 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 :)
If you want boost::bind to work with weak_ptr then just add the following
code before using bind.
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/preprocessor/inc.hpp>
#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/control/expr_if.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
#ifndef MAX_WEAK_FUNCTOR_ARGS
#define MAX_WEAK_FUNCTOR_ARGS 10
#endif
namespace detail
{
struct do_nothing {
typedef void result_type;
void operator()() const {}
};
template <class T>
struct weak_ptr_wrapper
{
explicit weak_ptr_wrapper(const boost::weak_ptr<T>& p) : p_(p) {}
#define BOOST_PP_LOCAL_MACRO(N) \
BOOST_PP_EXPR_IF(N, template <) \
BOOST_PP_ENUM_PARAMS(N, class Q) \
BOOST_PP_EXPR_IF(N, >) \
boost::function<void( BOOST_PP_ENUM_PARAMS(N, Q) )> \
operator ->* (void (T::*fun)( BOOST_PP_ENUM_PARAMS(N, Q))) \
{ \
if(boost::shared_ptr<T> p = p_.lock()) \
return boost::bind(fun, p BOOST_PP_COMMA_IF(N) \
BOOST_PP_ENUM_SHIFTED_PARAMS \
(BOOST_PP_INC(N), _)); \
else \
return boost::bind(do_nothing()); \
}
#define BOOST_PP_LOCAL_LIMITS (0, MAX_WEAK_FUNCTOR_ARGS)
#include BOOST_PP_LOCAL_ITERATE()
private:
boost::weak_ptr<T> p_;
};
}
namespace boost
{
template <class T>
::detail::weak_ptr_wrapper<T> get_pointer(const weak_ptr<T>& ptr)
{
return ::detail::weak_ptr_wrapper<T>(ptr);
}
}
And here is the test:
#include <iostream>
struct foo {
void f() { std::cout << "Hello" << std::endl; }
};
int main() {
boost::shared_ptr<foo> p(new foo);
boost::weak_ptr<foo> w(p);
boost::function<void()> f(bind(&foo::f, w));
f(); // prints "Hello"
p.reset();
f(); // does nothing
}
It does not have the best performance because boost::function is created
each time you call functor, but it can be easily improved by writing your
own function wrapper and using it instead of boost::function as a return
value from weak_ptr_wrapper::operator->.
HTH,
Roman Perepelitsa.
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