Слабые_птр и родительско-дочерние циклические зависимости - PullRequest
4 голосов
/ 18 декабря 2010

У меня сейчас есть что-то похожее на следующее:

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 до тех пор, пока ~ Child не закончит?

Ответы [ 5 ]

2 голосов
/ 28 ноября 2011

_parent.lock()->

Здесь вы предполагаете, что lock будет успешным, IOW, что ваш weak_ptr не истечет в то время.

Итак, вы вообще не должны использовать weak_ptr, а вместо shared_ptr.

Все будет намного яснее, если вы не злоупотребите weak_ptr. Вы увидите, что у вас есть два объекта, которые пытаются управлять временем жизни друг друга, и что ваш дизайн должен быть исправлен. (Бросок weak_ptr в смесь не исправляет дизайн.)

2 голосов
/ 18 декабря 2010

Первое правило слабого_птр: всегда проверяйте блокировку (возвращаемый указатель или исключение): ведь настоящая причина использовать слабый_птр в том, что он не контролирует жизненный цикл указанного объекта.

2 голосов
/ 18 декабря 2010

Желательно удалить круговую ссылку, но если вы не можете, вы можете заставить ребенка уничтожить до того, как родитель полностью исчезнет.В деструкторе явно вызовите reset () для Child.Это приведет к немедленному его уничтожению, при условии, что в нем нет других shared_ptrs.

Предупреждение: если родительский класс действительно является базовым классом, все его подклассы будут уже уничтожены.Вызовы виртуальных функций, вероятно, не будут вести себя должным образом.

2 голосов
/ 18 декабря 2010

Поскольку к тому времени, когда вызывается деструктор для дочернего элемента, деструктор родительского объекта уже запущен (dtors для объектов-членов запускаются после dtor для содержащего объекта), даже если дочерний элемент имел простой указатель на родительский элемент вызов функции-члена родителя будет недействительным ко времени вызова ~Child().

Возможно, вам удастся обойти эту проблему, попросив ребенка позвонить getSystem() в более раннюю точку и кэшировать результат. Может быть, в конструкторе Child (если у него есть ссылка на родителя в то время) или может быть добавлен интерфейс, чтобы Parent мог дать ребенку понять, что ему нужно собрать все, что ему может понадобиться во время уничтожения, из родитель в то время.

Я понимаю, что ни одно из них не является отличным решением (оно увеличивает сцепление объектов) - надеюсь, кто-то опубликует лучший вариант.

0 голосов
/ 18 декабря 2010

Только из кода, который вы разместили, это должно работать.Единственное, что удаляет _child - это родительский класс.

Таким образом, есть две возможности: во-первых, что-то еще также имеет ссылку на указатель _child и сохраняет счетчик ссылок живым, а затем родительский объект уничтожается.Затем, в конечном счете, все, что удерживает дочерний элемент, также уничтожается, тогда убивается дочерний элемент.

Сценарий 2 заключается в том, что вызов getSystem зависит от некоторых других членов, которых вы нам не показываете, и которые удаляются до _childshared_ptr is.

...