2016-07-15 6 views
9

Как я понимаю, make_shared<T>(...) может обеспечить некоторую оптимизацию распределения памяти (он может выделять опорный счетчик в том же блоке памяти, что и экземпляр класса T).Имеет ли enable_shared_from_this и make_shared такую ​​же оптимизацию

Действительно ли enable_shared_from_this обеспечивает ту же оптимизацию? Итак:

class T : std::enable_shared_from_this<T> {}; 
... 
auto t = std::shared_ptr<T>(new T); 

То же самое, как:

class T {}; 
... 
auto t = std::make_shared<T>(); 

Если не принимать во внимание SizeOf (Т).

+5

Эти два полностью ортогональны. 'enable_shared_from_this' имеет значение, если вы уже имеете * общий указатель. –

+0

@KerrekSB Я полагаю, что enable_shared_from_this добавляет некоторые данные в класс, который может использоваться при реализации общего указателя. Что касается меня, то самый простой способ - разместить количество ссылок как часть enable_shared_from_this, и это может помочь уменьшить выделение памяти в первом случае. –

+0

У меня возникает соблазн сказать «да», так как в противном случае невозможно извлечь блок refcount изнутри объекта. Но это просто догадка. – Quentin

ответ

8

Действительно ли enable_shared_from_this обеспечивает ту же оптимизацию? Итак:

No. Как видно из формулировки стандарта, enable_shared_from_this<T> имеет элемент в weak_ptr<T> данных. Это добавляет weak_ptr<T> к классу, который имеет указатель на блок управления, содержащий количество ссылок. Он не содержит счетчики ссылок напрямую. Блок управления, содержащий ссылочные счеты, по-прежнему существует вне объекта.

Контрольный блок, содержащий ссылочные подсчеты, должен пережить объект, так что другие объекты weak_ptr, которые использовали для ссылки на объект, могут получить доступ к блоку управления, чтобы проверить, истек ли он.

Если контрольный блок находился внутри объекта, он был бы уничтожен, когда объект был уничтожен, и было бы невозможно, чтобы оборванный weak_ptr безопасно определял, истек ли объект. Теоретически память блока управления может оставаться выделенной и все еще использоваться, а контрольные подсчеты обновляются, хотя объект, из которого они были частью, был уничтожен, но это кажется довольно уродливым (и это будет означать, что объект не будет уничтожен с помощью delete , для этого потребуется явный вызов деструктора и явный вызов operator delete, чтобы освободить память).

Вы также не могли использовать встроенный блок управления, если владелец shared_ptr был создан с помощью пользовательского делетера или настраиваемого распределителя, поскольку размер этих объектов не был бы заранее известен. В таких случаях вам еще нужно будет выделить внешний блок управления в дополнение к, который был встроен в базовый класс enable_shared_from_this<T>, тратя еще больше места.

+0

Спасибо за прекрасное объяснение! –

+0

Это довольно интересный вопрос, но чем больше я думаю о том, как это будет работать, тем больше сложностей я нахожу. –

+0

Я полагаю, что в случае, если make_shared память экземпляра также не может быть освобождена до тех пор, пока последняя функция weak_ptr не будет указана на блок управления. Но в отличие от enable_shared_from_this, он может быть четко реализован из точки языка C++ (не используйте уничтоженный объект). –