weak_ptr和父子循环依赖
我目前有类似以下内容:
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();
}
}
Child 析构函数总是崩溃,因为当 ~Child() 运行时 _parent 总是过期。对于这种奇怪的现象有典型的解决方案吗?
简而言之,有没有办法在 ~Child 完成之前不销毁 _parent ?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
因为当子对象的析构函数被调用时,父对象的析构函数已经运行(成员对象的 dtor 在包含对象的 dtor 之后运行),即使子对象持有指向父对象的普通指针,调用调用
~Child()
时,父级的成员函数将无效。您可以通过让 Child 在早些时候调用
getSystem()
并缓存结果来解决此问题。也许在Child
的构造函数中(如果它当时有对父级的引用),或者可能可以添加一个接口,以便Parent
可以让子级知道它需要从当时的父级收集销毁过程中可能需要的任何东西。我知道这两个都不是一个很好的解决方案(它增加了对象的耦合) - 希望有人会发布更好的选择。
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 ofChild
(if it has a reference to the parent at the time) or maybe there can be an interface added so thatParent
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.
最好删除循环引用,但如果不能,您可以强制在 Parent 完全消失之前销毁 Child。在析构函数中,显式调用 Child 上的 Reset()。假设没有其他共享指针,这将迫使它立即被销毁。
警告,如果 Parent 实际上是基类,那么它的所有子类都将被销毁。虚函数调用可能不会按预期运行。
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.
weak_ptr 的第一条规则:始终检查锁定(返回指针或异常):毕竟使用weak_ptr 的真正原因是它不控制所指向对象的生命周期。
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.
这里你假设
lock
会成功,并且你的weak_ptr
当时还没有过期。因此,您根本不应该使用
weak_ptr
,而应该使用shared_ptr
。如果您不滥用<代码>weak_ptr。您将看到有两个对象试图管理彼此的生命周期,并且您的设计需要修复。 (将
weak_ptr
添加到混合中并不能修复设计。)Here you assume that
lock
will succeed, IOW that yourweak_ptr
will not have expired at that time.So, you should not be using a
weak_ptr
at all, but ashared_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. (Throwingweak_ptr
into the mix does not fix a design.)仅从您发布的代码来看,这应该可行。唯一删除_child的是父类。
因此有两种可能性:首先,其他东西也有对 _child 指针的引用,并使其引用计数保持活动状态,然后parent 被销毁。然后最终任何其他抓住孩子的东西也会被摧毁,然后杀死孩子。
场景 2 是对 getSystem 的调用取决于您未向我们展示的其他一些成员,并且这些成员在 _child shared_ptr 之前被删除。
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.