shared_ptr против CComPtr - PullRequest
       11

shared_ptr против CComPtr

4 голосов
/ 11 февраля 2012

Я немного привык к концепции пересчета через COM, и я немного новичок в shared_ptr.Есть несколько хороших свойств с CComPtr, которые я не нахожу в shared_ptr, и мне интересно, каков шаблон, который предотвращает неправильное использование shared_ptr.

  • Шаблон AddRef / Release гарантирует, что тамэто только один refcount на объект (refcount хранится на самом объекте), так что это безопасно, когда у вас есть случайный указатель для создания CComPtr вокруг него.С другой стороны, shared_ptr имеет отдельный указатель refcount, поэтому небезопасно создавать новый shared_ptr для объекта (почему стандарт предоставляет конструктор, который принимает T * для shared_ptr, если это так небезопасно?).Это кажется таким большим ограничением, что я не понимаю, как можно использовать shared_ptrs ...

  • Небольшой угловой случай: то, что я делал в прошлом с AddRef / Release: Я хочу контейнер "слабых ссылок" на IFoos (например, карту от URL-адреса до IConnection или что-то).Слабый_птр, я могу это сделать, но моя коллекция не будет «очищаться», у меня истек срок действия указателей.С помощью Release я могу реализовать свой собственный слабый указатель (немного работы), который на самом деле очищает коллекцию.Есть ли альтернатива с shared / weak_ptr?

  • Интуитивно понятно, что при создании двух объектов памяти для создания объекта (один для refcount, один для объекта) существует потеря производительности по сравнению сНеизвестный мир, где вы делаете только один.Существует также штраф за локальность при доступе к объекту (при условии, что за AddRef часто следует чтение содержимого объекта, что кажется вероятным).Сравнивалась ли стоимость обоих подходов?

1 Ответ

5 голосов
/ 12 февраля 2012

почему стандарт предоставляет конструктор, который принимает 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 и всеми , которые накладные расходы.

...