make_shared против shared_ptr

Краткое резюме:

Просто краткий обзор: общие указатели работают на основе концепции счетчика ссылок, они поддерживают отдельный блок управления, в котором хранится этот счетчик.

Как работает shared_ptr, так это то, что они поддерживают -

сильный счетчик ссылок (S) — количество общих_ptr(ов), поддерживающих объект в рабочем состоянии. Общий объект уничтожается (и, возможно, освобождается), когда исчезает последняя сильная ссылка.

weak reference count (W) — количество активных weak_ptr(ов), которые в данный момент наблюдают за объектом + (S!=0)

Количество Strong и Weak обычно увеличивается с помощью эквивалента atomic::fetch_add с memory_order_relaxed.

Уменьшение требует более строгого порядка для обеспечения безопасного уничтожения.

Логическая модель для конструктора shared_ptr

Если shared_ptr создается из существующего указателя, который не является shared_ptr, необходимо выделить память для управляющей структуры.

Этот блок управления уничтожается и освобождается, когда исчезает последний слабый реф. Подход к построению shared_ptr состоит из двух шагов.

Логическая модель построения объекта с помощью make_shared

make_shared (или allocate_shared) Выделяет память для управляющей структуры и самого объекта в одном блоке памяти.

Затем объект создается путем идеальной пересылки аргументов его конструктору.

Плюсы make_shared вместо shared_ptr

Производительность: уменьшено количество отдельных распределений.

Местность кеша: действия, которые работают как со структурой счетчика, так и с самим объектом, будут иметь вдвое меньшее количество промахов кеша. (В случае, если промахи кеша являются серьезной проблемой, мы можем вообще отказаться от работы с указателями на одиночные объекты)

Порядок выполнения и безопасность исключений: (касается версии до C++17)

Возможный порядок выполнения

1) new Lhs("foo"))
2) new Rhs("bar"))
3) std::shared_ptr‹Lhs›
4) std::shared_ptr‹Rhs›

И одно важное преимущество, особенно в случае кодов до C++17, — это безопасность выполнения. Итак, посмотрите на этот фрагмент. Foo имеет эту сигнатуру функции, вы делаете вызов следующим образом.. теперь, до С++ 17, нет ограничений на разрешение аргументов, поэтому одно из возможных разрешений может выглядеть так — теперь то, что выдает второй шаг.. у вас есть утечка , правильно?

Исправление 1.Используйте make_shared

Исправление 2: Расширение кода

Shared_ptr Pro и make_shared

Доступ к конструктору.make_shared требуется доступ к конструктору, который он должен вызывать.

Срок службы хранилища объектов (не самого объекта) —второе преимущество связано со сроком службы хранилища объектов (а не с объектом). Речь идет об уничтожении или освобождении, когда срабатывает последний слабый счет. , то произойдет только освобождение. В случае make_shared узким местом становится одиночный блок. Для объектов большого размера в сочетании с некоторым долгим сроком службы weak_ptr это может стать проблематичным.

С помощью shared_ptr вы также можете указать пользовательское средство удаления, если это необходимо!

Вывод: если нет веских причин, следуйте этому

Как правило, make_shared предпочтительнее, чем shared_ptr, но в некоторых случаях, как указано выше, может понадобиться и shared_ptr.

использованная литература



https://arne-mertz.de