Почему общий ptr должен проводить подсчет ссылок для слабого ptr?
цитата из C++ Primer $12.1.6:
A
weak_ptr
(таблица 12.5) является интеллектуальным указателем, который не управляет временем жизни объект на который он указывает. Вместо этого weak_ptr указывает на объект, который управляется аshared_ptr
. Создание и привязка к shared_ptr не меняет отсчет ссылок на этоshared_ptr
. Однажды последнийshared_ptr
указывая на объект исчезнет, сам объект будет удален. этот объект будет удален даже если естьweak_ptrs
указываю на это-отсюда и названиеweak_ptr
, который захватывает идея о том, чтоweak_ptr
долей объекта "слабо."
тем не менее, я прочитал статьи говорит:
использование make_shared более эффективно. Реализация shared_ptr должна поддерживать домашнюю информацию в блоке управления, совместно используемом всеми shared_ptrs и weak_ptrs, ссылающимися на данный объект. В частности, что хозяйственная информация должна включать не только один, но и два отсчета:
счетчик "сильная ссылка" для отслеживания количества shared_ptrs в настоящее время сохраняя объект живым. Общий объект уничтожается (и, возможно, освобождается), когда исчезает последняя сильная ссылка.
подсчет "слабой ссылки" для отслеживания количества weak_ptrs, наблюдающих в настоящее время объект. блок управления общей уборкой уничтожается и освобождается (и общий объект освобождается, если он еще не был), когда исчезает последняя слабая ссылка.
насколько я знаю,shared_ptr
создано make_shared
в том же блок управления С этими счетами ref.Таким образом, объект не будет выпущен до последнего weak_ptr
истекает.
вопросы:
-
это неправильно праймер?, потому что
weak_ptr
воля фактически влияет на время существования этого объекта. - почему
shared_ptr
нужно отслеживать его слабые ссылки?Weak_ptr может определить, существует ли объект, проверив сильный ссылок в блоках управления, поэтому я думаю, что блок управления не должен отслеживать слабые ссылки. -
просто для любопытства, что делает блок управления, созданный
shared_ptr
выглядеть?Это что-то вроде:template<typename T> class control_block { T object; size_t strong_refs; size_t weak_refs; void incre(); void decre(); //other member functions... }; //And in shared_ptr: template<typename T> class shared_ptr { control_block<T> block;//Is it like this?So that the object and refs are in the same block? //member functions... };
3 ответов
счетчик ссылок управляет временем жизни объекта, на который указывает объект. Слабый граф - нет, но тут контроль (или участие в контроле) срок службы блок управления.
если счетчик ссылок идет в 0
объект уничтожил, но не обязательно освобожден. Когда слабый счет идет в 0
(или когда счетчик ссылок становится равным 0
, если нет weak_ptr
s, когда это случается), блок управления уничтожается и освобождается, а хранилище для объекта освобождается, если оно еще не было.
разделение между уничтожение и освобождение указанная на объект деталь реализации вам не нужно заботиться, но это вызвано использованием make_shared
.
если у вас
shared_ptr<int> myPtr(new int{10});
вы выделяете хранилище для int
, затем передайте это в shared_ptr
конструктор, который выделяет хранилище для блока управления отдельно. В этом случае хранилище для int
может быть освобожден как можно раньше: как только счетчик ссылок попадает 0
, даже если есть еще слабая графа.
если у вас
auto myPtr = make_shared<int>(10);
затем make_shared
может выполнить оптимизацию, где он выделяет хранилище для int
и блок управления в одном дыхании. Это означает, что хранилище для int
нельзя освободить до хранения для блок управления также может быть освобожден. Жизни int
заканчивается, когда счетчик просмотров 0
, но хранилище для него не освобождается до тех пор, пока слабый счетчик не попадет 0
.
теперь понятно?
weak_ptr должен указывать на то, что может сказать, существует ли объект или нет, поэтому он знает, можно ли его преобразовать в shared_ptr. Поэтому для хранения этой информации необходим небольшой объект.
этот блок управления домашним хозяйством должен быть уничтожен при удалении последнего week_ptr (или shared_ptr). Поэтому он должен вести счет как shared_ptr, так и week_ptr.
обратите внимание, что блок управления уборкой не совпадает с объектом точка ПТР и поэтому week_ptr не влияют на жизнь объектов.
существует множество различных способов реализации интеллектуальных указателей в зависимости от того, какое поведение вы хотели бы иметь. Если вы хотите узнать больше, я бы рекомендовал "современный дизайн C++" Александреску (https://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315)
и weak_ptr и shared_ptr указывают на память, содержащую блок управления. Если вы удалите блок управления, как только счетчик shared_ptr достигнет 0 (но слабый счетчик этого не делает), вы останетесь с weak_ptrs, указывающим на память мусора. Затем, когда вы пытаетесь использовать weak_ptr, он считывает освобожденную память и происходят плохие вещи (UB).
по этой причине блок управления должен быть оставлен в живых (выделен и построен, не уничтожен и не освобожден), пока любой weak_ptr может попытаться прочитать он.
основной (заостренный) объект будет уничтожен и может (надеюсь) быть освобожден, как только общий счетчик достигнет 0. Блок управления будет уничтожен и освобожден, когда оба счетчика достигнут 0.