C++ 弱ptr和父子循环依赖

C++ 弱ptr和父子循环依赖,c++,pointers,cycle,shared-ptr,smart-pointers,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&g

我目前有一些类似于以下内容:

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(); 
    }
}
类父类
{
//只有一个孩子…为了简单起见
//没有其他类持有对子类的共享\u ptr引用
共享ptr儿童;
System*getSystem(){…}
}
班童
{
弱ptr父母;
~z~孩子
{ 
_parent.lock()->getSystem()->blah();
}
}
子析构函数总是崩溃,因为当~Child()运行时,父函数总是过期。有没有一个典型的解决办法


简而言之,有没有办法在~Child完成之前不销毁父对象?

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

您可以通过在较早的某个点调用子调用
getSystem()
并缓存结果来解决此问题。可能在
Child
的构造函数中(如果它当时引用了父级),或者可能添加了一个接口,以便
parent
可以让子级知道它需要从父级收集销毁期间可能需要的任何东西


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

删除循环引用是更好的选择,但如果不能,可以在父对象完全消失之前强制销毁子对象。在析构函数中,对子对象显式调用reset()。这将迫使它立即被销毁,前提是没有其他共享文件


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

仅从您发布的代码来看,这应该是可行的。唯一要删除的是父类

因此有两种可能性:首先,其他东西也有一个对_子指针的引用,并使其ref count保持活动状态,然后父指针被销毁。然后,最终任何其他抓住孩子的东西也被摧毁,杀死了孩子


场景2是对getSystem的调用取决于您没有向我们显示的其他一些成员,这些成员在_childshared _ptr被删除之前被删除。

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

\u parent.lock()->

这里假设
lock
将成功,前提是您的
弱\u ptr
届时不会过期

因此,您根本不应该使用
弱ptr
,而应该使用
共享ptr


如果你不误用
弱\u ptr
,事情就会清楚得多。您将看到有两个对象试图在生命周期内相互管理,您的设计需要修复。(将
weak_ptr
放入组合中并不能解决设计问题。)

从长远来看,循环依赖总是比首先消除它们需要花费更多的精力来维护。你的情况可能吗?我不太明白你的设计。为什么不从
Parent
的析构函数调用
getSystem()->blah()
?您的设计似乎颠倒了责任。@Johannes这只是一些存根代码:)这是如何不使用弱的东西来“修复”循环依赖性问题。我相信您正在寻找的成员是
清晰的
,不
reset
:)这听起来真的很像标准内存管理:)arr智能指针…@Bill ONeal:不,非常确定它在Boost中被重置(我认为这是共享ptr最常见的实现)。C++0x实现是否有不同的接口?对不起,我认为这是子对象的向量PIt不起作用,因为孩子的毁灭是由父母的毁灭煽动的(孩子归父母所有)。因此,在调用子函数的析构函数时,父函数的析构函数已经被调用(而父函数仍在析构函数的过程中)。