Reputation: 1167
I am exploring the use of std::function
and std::bind
. I see that you can bind a member function, for example:
class A{
int c_ = 10;
public:
int add(int a, int b){
return a + b + c_;
}
};
int main(){
A* p_a = new A;
std::function<int()> f = std::bind(&A::add, p_a, 1, 1);
printf("%i\n", f()); // yields "12" (1 + 1 + 10)
delete p_a;
printf("%i\n", f()); // yields derpy numbers, no errors thrown.
}
Is there a way to detect if p_a has been deleted?
My solution to do this is having a wrapper class that holds the function and a weak_ptr
to the object. I am just wondering if there is a more elegant way to do this.
Upvotes: 2
Views: 896
Reputation: 275740
struct A{
int c_ = 10;
int add(int a, int b){
return a + b + c_;
}
};
template<class T>
std::weak_ptr<T> weak( std::shared_ptr<T> const& sp ) { return {sp}; }
int main(){
auto p_a = std::make_shared<A>();
std::function<int()> f = [w_a = weak(p_a)]() {
if (auto p_a = w_a.lock())
return p_a->add(1,1);
throw w_a;
}
printf("%i\n", f()); // yields "12" (1 + 1 + 10)
p_a.reset();
try {
printf("%i\n", f()); // yields derpy numbers, no errors thrown.
} catch( std::weak_ptr<A> wp ) {
printf("object deleted\n");
}
}
in general, in C++ you don't pay for what you don't use.
Tracking the lifetime of objects has a cost. If you want to track the lifetime of objects, you can use a shared_ptr
or weak_ptr
to the (free-store) allocated object, or use a weak_ptr
to a shared_ptr
(uniquely) owned by the object to indicate its lifetime is over.
The above is an implementation using C++14 lambdas to capture the object's shared pointer as a weak ptr, and give defined behavior (a throw of a copy of said weak pointer) if it has been deleted.
A lifetime token looks like:
using lifetime_token = std::weak_ptr<void>;
struct has_lifetime {
has_lifetime():token(std::make_shared<char>()) {}
has_lifetime(has_lifetime const&o):has_lifetime() {} // not default
lifetime_token get_lifetime() const {
return token;
}
private:
std::shared_ptr<void> token;
};
inheriting from has_lifetime
gives you a get_lifetime()
member that exists for as long as you do (it is destroyed by your destructor, and can no longer be .lock()
d).
This is an easier pattern to follow if you cannot modify the ownership semantics of the original class. Simply .lock()
the lifetime_token
of the object to determine if it is still alive.
Upvotes: 3
Reputation: 15568
std::bind
can accept smart pointers, so you can simply pass std::shared_ptr<A>
to it.
std::shared_ptr<A> p_a(new A);
std::function<int()> f = std::bind(&A::add, p_a, 1, 1);
Note, that the functor will own the object: the object will live as long as the functor lives. If you don't want such behavior, then your solution with a weak_ptr
wrapper is nice.
Upvotes: 5