Я сбился с пути, @einpoklum понял все правильно.
Вы не можете создать более одного shared_ptr
из одного и того же обычного указателя. Все остальные shared_ptr
должны быть копиями другого shared_ptr
.
Это потому, что shared_ptr
должен выделить другой объект, который поддерживает счетчик ссылок для вашего объекта, и это делает конструктор shared_ptr
из простого простого указателя *1014*. shared_ptr
конструкторы копирования просто увеличивают счетчик ссылок.
Когда вы создаете несколько shared_ptr
с одного и того же указателя plain , они выделяют свои собственные счетчики ссылок и в конечном итоге удаляют ваш объект несколько раз. Что приводит к неопределенному поведению (часто происходит сбой при втором удалении).
Существует также boost::intrusive_ptr
, который ожидает, что счетчик ссылок будет внутри объекта. Следовательно, несколько boost::intrusive_ptr
могут быть созданы из одного и того же указателя plain , поскольку все они используют один и тот же счетчик ссылок внутри объекта.
boost::intrusive_ptr
также более эффективен, чем shared_ptr
, но не поддерживает слабые указатели.
boost::intrusive_ptr
более эффективен, поскольку он имеет тот же размер, что и обычный указатель (размер shared_ptr
в два раза больше), поскольку ему не нужно выделять отдельную структуру со счетчиком ссылок и объектом удаления в другом месте и держать еще один указатель на это.
В многопоточном приложении shared_ptr
всегда использует более дорогой атомарный прирост / декремент для обслуживания счетчика ссылок, даже если вы никогда не передаете эти указатели через потоки. В хорошо спроектированном приложении только shared_ptr
s для определенных T
s когда-либо передаются через потоки, и только эти shared_ptr<T>
s должны использовать атомный счетчик. С boost::intrusive_ptr
вы используете атомарный счетчик только для объектов, которые передаются между потоками, и используете простой целочисленный счетчик для остальных ваших объектов.