shared_ptr, subscription, destructor
-
20-09-2019 - |
Question
I'm using Boost/shared_ptr pointers throughout my application. When the last reference to an object is released, shared_ptr will delete the object for me. The objects in the application subscribes to events in a central location of the application, similar to the observer/subscriber pattern.
In the object destructors, the object will unsubscribe itself from the list of subscriptions. The list of subscriptions is essentially just a list<weak_ptr<MyObject> >
. What I want to do is something similar to this:
Type::~Type()
{
Subscriptions::Instance()->Remove(shared_from_this());
}
My problem here is that shared_from_this cannot be called in destructors so the above code will throw an exception.
In my old implementation, the subscription list was just a list of pointers and then it worked. But I want to use weak_ptr references instead to reduce the risk of me screwing up memory by manual memory management.
Since I rely on shared_ptr to do object deletion, there's no single place in my code where I can logically place a call to Unsubscribe.
Any ideas on what to do in this situation?
Solution
- You can destroy the objects via Subscription instance, then it'll automatically remove the pointers.
- You can forget about removing them from subscriptions -- the weak_ptr's wont be able to be locked anyway, then you can remove them.
- You can assign an unique ID to every object and then remove via the unique ID not the shared_ptr
- You can pass a normal pointer to Remove instead of a shared one -- it will serve as an "ID".
OTHER TIPS
My problem here is that
shared_from_this
cannot be called in destructors so the above code will throw an exception.
It will throw an exception because it's expired, by definition, in a destructor.
So what do you want anyway? An "expired" shared pointer? Just create an empty shared pointer.
Or an expired weak pointer?
Maybe if you notice that the "problem" isn't shared_from_this
throwing (it's a symptom) but all owners being inherently already reset or destroyed at that point and the weak pointers being expired and equivalent to an empty default created weak pointer (*), so you just should pass a default initialized weak pointer.
Also Subscriptions::Instance()->Remove(weak_OR_owning_pointer)
makes no sense either way (with either weak or owning pointer) as you can't compare a weak pointer to anything, you can only try to lock it (and then do a comparison).
So you can just remove expired weak pointers. The arguments of Remove
is useless.
(*) either that OR you have a very serious double bug of double ownership of the object being destroyed!