подсчет ссылок с циклами в C ++ умный указатель - PullRequest
2 голосов
/ 27 февраля 2010

В интеллектуальном указателе shared_ptr используется подсчет ссылок. Однако у подсчета ссылок есть проблема, заключающаяся в том, что он не может разорвать циклы ссылок.

У меня есть четыре вопроса с этим вопросом.

1) Может кто-нибудь предложить мне один фрагмент, в котором произошли циклы ссылок?

2) Если он не может разорвать циклы обращения, как RCSP гарантирует успешное управление ресурсами? Есть ли способ разорвать циклы с помощью стороннего продукта?

3) Есть ли способ избежать циклов обращения?

4) Как насчет других умных указателей? Как они справляются с источником управления? Например, share_ptr, scope_ptr?

Большое спасибо!

Ответы [ 2 ]

10 голосов
/ 27 февраля 2010

Обычный способ избежать циклов - использовать слабые ссылки в любой точке цикла. shared_ptr имеет тип компаньона, weak_ptr, который предназначен для этой цели.

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

6 голосов
/ 27 февраля 2010

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

struct node {
    node *next;
};

int create_cycle() {
    node *a = new node;
    a.next = a;
}

После возврата create_cycle только что выделенный нами узел содержит ссылку на себя, но другой точки для этого нет, поэтому счетчик ссылок не будет собирать его, даже если он является мусором.

Крис Джестер-Янг уже имел дело с прерыванием цикла с помощью умных указателей с практической точки зрения. Хотя он не вдавался в подробности о том, как это работает внутри.

Слабый_птр является двояко-косвенным указателем. То есть strong_ptr не дает доступа напрямую к объекту. Вместо этого, чтобы добраться до объекта, вы должны преобразовать слабый_птр в shared_ptr, а затем использовать его для доступа к объекту - но попытка преобразовать слабый_птр в общий_птр будет успешной, только если еще есть хотя бы один другой shared_ptr для управляемый объект (поэтому объект имеет ненулевое число ссылок и все еще существует).

Как таковой, слабый_птр дает вам доступ к объекту, пока он существует, но «знает», когда объект перестает существовать, и не дает вам доступ к (теперь освобожденной) памяти, где раньше был объект. если объект был уничтожен.

Избегание циклов зависит от того, с чем вы работаете. Если вы много работаете с графиками (для одного примера), их часто практически невозможно избежать, просто потому, что довольно много вещей, которые вы моделируете, имеют циклы. В противном случае, хорошо ... это зависит. Я предполагаю, что изрядное количество разработчиков ушло на всю карьеру без необходимости создавать связанную структуру, которая содержит цикл. Другие, вероятно, делают это несколько раз в неделю.

Что касается других интеллектуальных указателей, то, как отмечено выше, тип weak_ptr работает в сочетании с shared_ptr; Вы можете использовать shared_ptr, даже не используя слабый_птр, но чтобы в какой-то момент реально использовать слабый_птр, вам необходимо преобразовать его в shared_ptr.

...