У KeithB есть действительно хорошее замечание, которое я хотел бы расширить (в смысле, который не связан с вопросом, но который не будет вписываться в комментарий):
В конкретном случае связи объекта с его подобъектами время жизни гарантировано: родительский объект всегда будет переживать дочерний объект. В этом случае дочерний (член) объект не не разделяет владение родительским (содержащим) объектом, и shared_ptr
не следует использовать. Его не следует использовать по семантическим причинам (без общего владения) или по практическим причинам: вы можете создавать всевозможные проблемы: утечки памяти и неправильные удаления.
Чтобы облегчить обсуждение, я буду использовать P
для ссылки на родительский объект и C
для ссылки на дочерний или содержащийся объект.
Если время жизни P
обрабатывается извне с помощью shared_ptr
, то добавление еще одного shared_ptr
в C
для ссылки на P
приведет к созданию цикла. Когда у вас есть цикл в памяти, управляемый подсчетом ссылок, вы, скорее всего, будете иметь утечку памяти: когда последний внешний shared_ptr
, который ссылается на P
, выходит из области видимости, указатель в C
все еще жив, поэтому ссылка значение для P
не достигает 0, и объект не освобождается, даже если он больше не доступен.
Если P
обрабатывается другим указателем, то когда указатель будет удален, он вызовет деструктор P
, который будет каскадно вызывать деструктор C
. Счетчик ссылок для P
в shared_ptr
, который есть у C
, достигнет 0 и приведет к двойному удалению.
Если P
имеет автоматическую продолжительность хранения, когда вызывается его деструктор (объект выходит из области видимости или вызывается деструктор содержащего объекта), тогда shared_ptr
инициирует удаление не нового блока памяти -ed.
Распространенным решением является разрыв циклов с weak_ptr
с, чтобы дочерний объект не оставлял shared_ptr
для родителя, а скорее weak_ptr
. На этом этапе проблема та же: для создания weak_ptr
объект должен уже управляться shared_ptr
, чего во время строительства не может быть.
Подумайте об использовании либо необработанного указателя (обработка владения ресурсом через указатель небезопасна, но здесь владение обрабатывается внешне, так что это не проблема), либо даже ссылки (которая также говорит другим программистам, что вы доверяете упомянутому объект P
чтобы пережить ссылающийся объект C
)