weak_ptr和父子循环依赖

时间:2010-12-18 01:04:57

标签: c++ pointers cycle shared-ptr smart-pointers

我目前有类似以下的内容:

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时总是过期。这种奇怪的解决方案是否有典型的解决方案?

简而言之,有没有办法不破坏_parent直到〜孩子完成?

5 个答案:

答案 0 :(得分:2)

因为到子节点的析构函数被调用时,父节点的析构函数已经运行(成员对象的dtors在包含对象的dtor之后运行),即使子节点持有指向父节点的普通指针在调用~Child()时,调用父成员函数将无效。

您可以通过让Child在某个早期点调用getSystem()并缓存结果来解决此问题。也许在Child的构造函数中(如果它当时有对父项的引用)或者可能会添加一个接口,以便Parent可以让孩子知道它需要收集任何可能的东西在当时父母的破坏期间需要。

据我所知,这些都不是一个很好的解决方案(它增加了对象的耦合) - 希望有人会发布更好的选择。

答案 1 :(得分:2)

最好删除循环引用,但如果不能,则可以在Parent完全消失之前强制销毁Child。在析构函数中,显式调用Child上的reset()。这将迫使它立即被销毁,假设没有其它的shared_ptrs。

警告,如果Parent实际上是一个基类,那么它的所有子类都将被销毁。虚函数调用可能不会按预期运行。

答案 2 :(得分:2)

weak_ptr的第一条规则:总是检查锁定(返回指针或异常):毕竟使用weak_ptr的真正原因是它不能控制指向对象的生命周期。

答案 3 :(得分:2)

  

_parent.lock()->

此处您假设lock会成功,因此您的weak_ptr当时不会过期。

所以,您根本不应该使用weak_ptr,而应使用shared_ptr

如果你不滥用weak_ptr,情况会更加明确。您将看到有两个对象试图管理彼此的生命周期,并且您的设计需要修复。 (向混合物中投掷weak_ptr不会修复设计。)

答案 4 :(得分:0)

从您发布的代码中,这应该可行。删除_child的唯一内容是父类。

所以有两个可能性:首先,其他东西也有一个对_child指针的引用,并保持ref count count,然后父类被销毁。然后最终还有其他什么东西也会被摧毁,然后杀死了孩子。

场景2是对getSystem的调用取决于你没有向我们展示的其他一些成员,并且在_child shared_ptr之前会被删除。