почему стандарт предоставляет конструктор, который принимает T * для shared_ptr, если это так небезопасно?
Потому что это единственный способ получить shared_ptr
s, не будучи навязчивым .Вы можете использовать shared_ptr
на что угодно .Я даже использовал их на объектах из C-интерфейсов, используя объект-удалитель.Такие вещи, как cairo_t*
и так далее.Таким образом, мне больше никогда не придется ничего освобождать.
Вы не можете сделать это с CComPtr
;он работает только для объектов IUnknown
-стиль.
Также существует std::make_shared
, который создает shared_ptr
непосредственно из типа объекта и аргумента конструктора.Таким образом, вы даже не видите указатель (и он обычно размещает объект и его ref-count в одном расположении вместо двух).
Правильный идиом C ++ с shared_ptr
очень прост: всегда используйте make_shared
или alloc_shared
.Если вы не можете использовать их, то правильная идиома заключается в том, чтобы only использовать конструктор прямого голого указателя вместе с new
: shared_ptr<T> pVal{new T{...}};
(или соответствующей функцией, которая создаетуказатель).Никогда не используйте его для указателей, происхождение которых вы не знаете.
Есть ли альтернатива с shared / weak_ptr?
Нет, но есть инструменты, которые нужно сделатьодин, если вы так желаете.Помимо очевидного метода (периодически просматривайте вашу коллекцию и удаляйте мертвые weak_ptr
s), вы можете связать удалитель с shared_ptr
, который (в дополнение к удалению указателя) вызовет любую функцию очистки для удаления этих weak_ptr
s..
Интуитивно понятно, что при выполнении двух выделений памяти для создания объекта существует потеря производительности
См. make_shared
выше.
Существует также штраф за локальность при доступе к объекту (при условии, что за AddRef часто следует чтение содержимого объекта, что кажется вероятным).
Вам не нужно копировать shared_ptr
, чтобы поговорить с его содержимым, и вам не нужно увеличивать счетчик ссылок, чтобы сделать это.
Теперь давайте поговорим о некоторых вещах, которые CComPtr
не может сделать.Это навязчиво.Его нельзя использовать с произвольными распределителями или удалителями (очевидно, не так важно, когда это навязчиво).Он не может выполнять псевдонимы указателей, когда у вас есть shared_ptr
для члена объекта, но фактический счетчик ссылок для объекта, членом которого он является.Это очень полезная вещь.
Ах да, это не кроссплатформенный .Это не связано с COM, IUnknown
и всеми , которые накладные расходы.