weak_ptr and parent-child cyclic dependencies
I currently have something similar to the following:
class Parent
{
//just a single child... for sake of simplicity
//no other class holds a shared_ptr reference to child
shared_ptr<Child> _child;
System * getSystem() {...}
}
class Child
{
weak_ptr<Parent> _parent;
~Child
{
_parent.lock()->getSystem()->blah();
}
}
The Child destructor always crashes, since when ~Child() runs _parent is always expired. Is there a typical solution to this weirdness?
In short, is there a way to not destroy _parent开发者_运维百科 until ~Child finishes?
Since by the time the destructor for the the child gets called, the parent's destructor has already run (dtors for member objects get run after the dtor for the containing object), even if the child was holding a plain pointer to the parent, calling the parent's member function would be invalid by the time ~Child()
was called.
You might be able to work around this by having Child call getSystem()
at some earlier point and cache the result. Maybe in the constructor of Child
(if it has a reference to the parent at the time) or maybe there can be an interface added so that Parent
can let the child know it needs to collect whatever it might need during destruction from the parent at that time.
I understand that neither of these is a great solution (it increases coupling of the objects) -hopefully someone will post a better option.
Removing the circular reference is preferable, but if you cannot you can force Child to be destroyed before Parent is completely gone. In the destructor, explicitly call reset() on Child. This will force it to be destroyed immediately, assuming there are no other shared_ptrs to it.
Warning, if Parent is actually a base class all of it's subclasses will alreayd have been destroyed. Virtual function calls will probably not behave as expected.
First rule of weak_ptr: always check the locking (returned pointer or exception): after all the real reason to use weak_ptr is that it doesn't control the life-cycle of the pointed object.
_parent.lock()->
Here you assume that lock
will succeed, IOW that your weak_ptr
will not have expired at that time.
So, you should not be using a weak_ptr
at all, but a shared_ptr
instead.
Things will be much more clear if you do not misuse weak_ptr
. You will see that you have two objects that try to manage each other lifetime, and that your design needs to be fixed. (Throwing weak_ptr
into the mix does not fix a design.)
Just from the code you posted this should work. The only thing deleting _child is the parent class.
So there are two possibilites: First, something else also has a reference to the _child pointer, and keeps it ref count alive, and then parent is destroyed. Then eventually whatever else is holding onto child is also destroyed, killing off the child then.
Scenario 2 is that the call to getSystem depends on some other members youre not showing us, and those are getting deleted before the _child shared_ptr is.
精彩评论