В каком смысле weak_ptr «владеет» shared_ptr?

Я пытался написать заголовок к этому вопросу около 10 минут, и, как вы увидите, в конце концов мне это не удалось. [Примечание редактора: кажется, я это исправил.]

Я читал блог Херба Саттера, и в теме используется std::make_shared, его минусы и плюсы. Пожалуйста, смотрите прикрепленное фото:

введите здесь описание изображения

Это небольшая часть очень-очень интересной статьи которую я настоятельно рекомендую людям прочитать. Мой вопрос касается этой фразы:

Счетчик «слабых ссылок» для отслеживания числа слабых точек, наблюдающих в данный момент за объектом. Общий блок управления обслуживанием уничтожается и освобождается (и общий объект освобождается, если он еще не был удален), когда исчезает последняя слабая ссылка.**

Я не очень понимаю это утверждение. Первоначально, когда мы создаем std::shared_ptr по make_shared, например. auto sp1 = make_shared<widget>();, в настоящее время нет слабых ptrs, наблюдающих за sp1, поэтому он будет удален, когда shared_ptr выйдет из области видимости обычным способом.

Так как же добавление слабой ссылки меняет это поведение? Кто-нибудь может объяснить мне это, пожалуйста?


person Eduard Rostomyan    schedule 12.06.2018    source источник
comment
Второй пункт подчинен первому: сначала вам нужно, чтобы все общие ссылки исчезли, прежде чем вы вообще что-либо сделаете. Затем вы также ждете, пока слабые ссылки исчезнут, прежде чем освобождать блок управления.   -  person Kerrek SB    schedule 12.06.2018
comment
Таким образом, освобождение блока управления, вызванное weak_count == 0, происходит только после того, как источник уже был удален, а strong_count равен 0?? @КеррекСБ   -  person Eduard Rostomyan    schedule 12.06.2018
comment
Что именно вы спрашиваете? Если сильное число не равно нулю, очевидно, что ни общий объект, ни управляющий блок не могут быть освобождены.   -  person Praetorian    schedule 12.06.2018
comment
Спасибо @Praetorian, это то, о чем я спрашивал!   -  person Eduard Rostomyan    schedule 12.06.2018
comment
@ЭдуардРостомян: Да. Когда сильное количество достигает 0, принадлежащий объект уничтожается, и дальнейшие доли не могут быть извлечены. Затем, когда счетчик слабых указателей достигает 0, управляющий блок уничтожается. Если слабых указателей нет, два события совпадают.   -  person Kerrek SB    schedule 13.06.2018


Ответы (2)


Блок управления отслеживает все ссылки weak_ptr, а также ссылки shared_ptr. В конце концов, weak_ptr должен искать где-то, чтобы убедиться, что объект все еще действителен.

Следовательно, блок управления не может быть освобожден до тех пор, пока все shared_ptrs и все weak_ptrs не будут уничтожены. Если вы используете make_shared, блок управления и объект размещаются вместе, что в основном является оптимизацией, за исключением случаев, если объект пережил какие-либо weak_ptrs.

person ravnsgaard    schedule 12.06.2018
comment
Если вы используете make_shared, управляющий блок и объект выделяются вместе, что в основном является оптимизацией, за исключением случаев, когда объект пережил любой weak_ptrs. — Просто хочу отметить, что даже если выделенная память, содержащая и блок управления, и объект не освобождаются перед всеми общими/слабыми указателями, объект, вероятно, уничтожается после последнего общего указателя. - person Holt; 12.06.2018
comment
@holt Да, действительно, деструктор будет вызван, но память не будет выделена. Однако хороший момент. - person ravnsgaard; 12.06.2018

Проще говоря, shared_ptr владеет управляемым объектом и метаинформацией (блоком управления), а weak_ptr владеет только метаинформацией.

Собственность означает, что:

  • когда у ресурса есть владелец, он не уничтожается (или «освобождается» способом, определенным при создании «умного указателя» владельца);
  • когда время жизни всех владельцев закончилось, ресурс уничтожается/освобождается.

Часть подсчета ссылок является деталью реализации. (Вы могли бы иметь связанный список, если вам нравятся очень неэффективные реализации с мьютексом вместо относительно эффективных атомарных счетчиков.)

person curiousguy    schedule 12.06.2018