Is there a way to std::bind to a std::weak_ptr? I'd like to store a "weak function" callback that automatically "disconnects" when the callee is destroyed.
I know how to create a std::function using a shared_ptr:
std::function<void()> MyClass::GetCallback()
{
return std::function<void()>(std::bind(&MyClass::CallbackFunc, shared_from_this()));
}
However the returned std::function keeps my object alive forever. So I'd like to bind it to a weak_ptr:
std::function<void()> MyClass::GetCallback()
{
std::weak_ptr<MyClass> thisWeakPtr(shared_from_this());
return std::function<void()>(std::bind(&MyClass::CallbackFunc, thisWeakPtr));
}
But that doesn't compile. (std::bind will accept no weak_ptr!) Is there any way to bind to a weak_ptr?
I've found discussions about this (see below), but there seems to be no standard implementation. What is the best solution for storing a "weak function", in particular if Boost is not available?
Discussions / research (all of these use Boost and are not standardized):
- weak_function
- weak_ptr binding
- "weak" binding (and a fix for it)
- weak_fn
- Another weak_fn
output:
I was able to create weak_pointers of std::function and tested it with clang-3.2 (you didn't give any compiler restrictions).
Here's a sample app that creates and tests what I believe you are asking for:
The output was:
How about this? it works only for actions
std::function<void()>
but perhaps it can be generalized for arbitrarily parameterized functions.here's an example usage:
Not sure why that definition is not in boost. There must be a good reason (how to deal with lock fail? Is throwing from there acceptable? Thread safety?) Anyway, that will validate your callee.
Another solution:
You could wrap the std::function. The class producing the callback would hold a shared_ptr< wrapper_type > and provide a weak_ptr< wrapper_type >. The producing object would be the one with the ownership, if it goes out of scope, callers won't be able to promote their weak reference. Your wrapper type could forward call arguments to the std::function or simply expose it via its interface. Just make sure that on copy you properly handle the shared_ptr on the wrapper (don't share).
You can bind
weak_ptr
to the function as one of parameters,and check it when the function is called.
For example:
You should never do this. Ever.
MyClass::CallbackFunc
is a non-static member function of the classMyClass
. Being a non-static member function, it must be called with a valid instance ofMyClass
.The entire point of
weak_ptr
is that it isn't necessarily valid. You can detect its validity by transforming it into ashared_ptr
and then testing if the pointer is NULL. Sinceweak_ptr
is not guaranteed to be valid at all times, you cannot call a non-static member function with one.What you're doing is no more valid than:
It may compile, but it will eventually crash when you try to call it.
Your best bet is to use actual logic, to not call the callback function if the
weak_ptr
is not valid.bind
is not designed to do logic; it just does exactly what you tell it to: call the function. So you need to use a proper lambda: