Почему enable_shared_from_this встроить слабый указатель вместо непосредственного встраивания счетчика ссылок?
Помощник enable_shared_from_this
содержит слабый указатель, который задается при создании общего указателя на объект. Это означает, что есть счетчик ссылок (выделенный отдельно или вместе с объектом с использованием make_shared
) и дополнительный weak_ptr
в объекте.
Теперь почему он просто не содержит счетчик ссылок? При установке shared_ptr
из немого указателя тип должен быть полностью определен, поэтому конструктор или оператор shared_ptr
может определить тип, полученный из enable_shared_from_this
, и использовать правильный счетчик, и формат может оставаться неизменным, поэтому копирование не волнует. Фактически, shared_ptr
уже должен обнаружить его для установки встроенного weak_ptr
.
Ответы
Ответ 1
Первое, что приходит на ум, это то, будет ли этот подход осуществимым вообще, и ответ заключается в том, что он не будет:
struct X : enable_shared_from_this {};
std::shared_ptr<X> p( new X );
std::weak_ptr<X> w( p );
p.reset(); // this deletes the object
if ( w.use_count() ) { // this needs access to the count object
// but it is gone! Undefined Behavior
Если счетчик хранится в объекте, то weak_ptr
может пережить объект, что является нарушением в контракте. Вся идея weak_ptr
заключается в том, что они могут пережить объект (если последний shared_ptr
выходит за пределы области видимости, объект удаляется, даже если есть weak_ptr
)
Ответ 2
Разделение проблем: make_shared
, чтобы вставить счетчик, enable_shared_from_this
для shared_from_this
.
Нет причин, по которым они должны быть смешаны: библиотека не может предположить, что клиентский код имеет для требований. Разделяя два, клиентский код может выбирать и выбирать все, что подходит лучше всего.
Кроме того, Boost (откуда shared_ptr
) также предлагает intrusive_ptr
.
(подумайте, что ваше предложение, похоже, не позволяет создавать пользовательские удалители. Вы можете исправить это, изменив enable_shared_from_this
на template<typename T, typename Deleter = default_deleter<T>> class enable_shared_from_this;
, но к этому моменту он приближается к переосмыслению intrusive_ptr
.)
Ответ 3
Чтобы получить какое-либо преимущество от встраивания счетчика в объект, вам понадобится
убрать второй указатель в shared_ptr
, который
изменить его компоновку, а также создать проблемы для создания деструктора
объект. Если вы измените макет, это изменение должно быть видимым
везде используется shared_ptr
. Это означает, что у вас не может быть
экземпляр shared_ptr
, указывающий на неполный тип.