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: что он использовал для