Shared_ptr и использование логического указателя в сложном дизайне
У меня есть объект A
, который содержит общий ресурс (shared_ptr) r
, A
является создателем/владельцем r
при построении объекта "регистрирует" его r
с другим объектом B. Объект B содержит ссылку на A
r
в std::set
. Объект A используется как обработчик Boost:: asio::.
Мне нужно отменить r
из B
, когда A
разрушается, а когда A
имеет уникальный доступ к r
, поскольку A
является r
создателем, он несет ответственность за его уничтожение, Примечание: A - копия, созданная несколько раз, когда она используется как boost:: asio handler. Удержание unque acces здесь означает, что операции asio не выполняются (потому что, если они были ссылочным числом, было бы > 2, так как были сделаны копии A
).
В настоящий момент уникальный доступ проверяется r.use_count() == 2
, поскольку A и B имеют доступ к объекту, когда не выполняются асинхронные операции. Тем не менее, я не считаю этот тест логически разумным.
Я думаю, что я должен изменить контейнер B с std::set<boost::shared_ptr<r> >
на std:set<boost::weak_ptr<r> >
, так что r.unique()
логически истинно, если не выполняются асинхронные операции. Является ли это разумным использованием weak_ptr
?
Конструктор и деструктор A
(in_process_invoker) и события регистрации (подключения) и отмена регистрации (disconect) выглядят следующим образом в моем коде:
in_process_invoker(BackEnd & b_in)
: client_data(new ClientData()),
b(b_in),
notification_object(new notification_object_())
{
b.connect(client_data);
}
~in_process_invoker()
{
if(client_data.unique())
{
b.disconect(client_data);
}
}
ИЗМЕНИТЬ
Я изменил свой дизайн на использование необработанных указателей, конструктор по умолчанию помещает invoker в качестве первичного invoker и его копии как не первичные. Когда первичный объект уничтожается, он освобождает память.
Ответы
Ответ 1
Если вы точно знаете, что ссылка, содержащаяся в B
, по-прежнему будет присутствовать, когда A
выполняет проверку количества ссылок, то зачем использовать какой-либо умный указатель в B
, почему бы не указать указатель на raw? И если вы не знаете, что B
по-прежнему будет содержать ссылку, то текущий тег == 2
не просто нечувствителен, он неверен.
Единственное преимущество, которое я вижу в weak_ptr
над необработанным указателем, заключается в том, что если вы измените вещи в будущем, чтобы A
не отменил регистрацию с B
, значит, ссылка может свисать, а затем weak_ptr
становится полезным сообщить B
, что произошло. Это может быть даже невозможно в зависимости от того, как B
использует r
: если дизайн в значительной степени зависит от того, что ссылка всегда действительна, тогда нет смысла пытаться покрыть случай, если это не так.
Вы можете использовать shared_ptr
везде, но если A
содержит ссылку на r
через shared_ptr
на прокси-объект, а B
содержит ссылку с shared_ptr
непосредственно на r
. Затем возложите ответственность за прокси-объект на отмену регистрации из B
. Таким образом, последняя копия A
, которая будет уничтожена, уничтожит прокси, и прокси-сервер отменит регистрацию с помощью B
, а затем уничтожит r
. Не нужно никому проверять use_count
.
Аналогичная опция для B
для хранения необработанного указателя и r
отменить регистрацию с B
в своем деструкторе. Это может быть сложнее сделать для потокобезопасности, я не уверен.
В идеале вы должны использовать "правильный" тип указателя для семантики владения. Если B
является совладельцем r
, тогда он должен иметь shared_ptr
, так что r
может спокойно пережить A
. Если B
не принадлежит r
, то используйте weak_ptr
, если r
не может быть незарегистрирован из B
до уничтожения (и убедитесь, что B
делает правильную вещь, когда истекает weak_ptr
) или необработанный указатель, если B
имеет гарантию от кого-то другого, чтобы гарантировать достоверность указателя.
Ответ 2
Нельзя смешивать интеллектуальные и необработанные указатели.
целая точка использования умных указателей - иметь способ
для управления освобождением объекта и
указатели подрывают это, поскольку нет способа
узнайте, действителен ли не-NULL raw-указатель.
Ваше решение с использованием слабых указателей кажется мне удобным
--- он четко отличает владение от неимущественного
Рекомендации. Я широко использовал
этот подход, когда некоторый объект A принадлежит одному
другой объект B, который удерживает его через долгоживущий
общий указатель, и тот же объект A также
ссылается на любое количество других объектов C-Z
через слабые указатели. См. Мой ответ на соответствующий вопрос: shared_ptr: что он использовал для