Почему std :: shared_ptr не использует ссылки?

std::shared_ptr Нужно выделить блок управления в куче, которая содержит счетчик ссылок. Был другой подход, из которого я узнал http://ootips.org/yonat/4dev/smart-pointers.html который хранит все ссылки в двусвязном списке. Он не требует дополнительных выделений или счетчика, но сам ссылочный объект больше.

Есть ли эталон или какая-либо явная причина, показывающая, что одна реализация лучше других?

3

Решение

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

Намного проще и в целом более эффективно выполнять подсчет ссылок с использованием атомарных типов и использовать атомарные операции для обновлений счетчика ссылок.

Редактировать: Чтобы ответить на комментарий ниже, недостаточно просто использовать атомарные указатели для реализации связанного списка. Чтобы добавить или удалить узел из списка (что соответствует увеличению или уменьшению use_count) вам нужно будет атомарно обновить два указателя, чтобы настроить ссылки в узлах до и после добавления / удаления одного из них. std::atomic<T*> позволяет обновлять один указатель атомарно, но не помогает, если вам нужно обновить два таких объекта атомарно. Поскольку эти два указателя находятся в отдельных узлах, они не являются смежными, поэтому даже четырехзначное CAS не поможет.

Альтернативы — это мьютекс, защищающий весь список (очевидно, плохой для конкуренции), или мьютекс на узел списка, где вы блокируете мьютекс каждого узла, участвующего в любом обновлении, который использует больше памяти и затрагивает до трех узлов одновременно, т.е. требует блокировки три мьютекса. Если у вас есть use_count() меньше или равно пяти, затем копирование / уничтожение любого shared_ptr конкурирует с копированием / уничтожением любого другого экземпляра, который разделяет владение тем же указателем. Вы можете получить меньше конфликтов с большим количеством использований, когда большинство обновлений находятся на соседних узлах, удаленных друг от друга, но, вероятно, не в общем случае. Множество программ используют shared_ptr с использованием рассчитывается в однозначных цифрах. Даже когда количество использований велико и на каких-либо узлах нет конфликтов, вам все равно придется заблокировать три мьютекса и создать / уничтожить узел списка (возможно, требующий выделения кучи) и обновить указатели на соседних узлах, так что атомарный прирост / декремент намного проще и все еще может быть быстрее, несмотря на спор об атомных целых числах.

В прошлый раз я упомянул в рефлексе комитета, что shared_ptr не требуется использовать количество ссылок и может использовать список, я получил ответы:

Кто-нибудь на самом деле делает это, учитывая, что Стандарт теперь распознает многопоточность?

и (в отношении требований безопасности нитей):

Гораздо сложнее заставить это работать (эффективно) для ссылочной реализации. Я даже не уверен, что это возможно, хотя это может быть.

8

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]