Ховард уже хорошо ответил на этот вопрос, и Никол сделал несколько хороших замечаний о преимуществах наличия единого стандартного типа общего указателя, а не множества несовместимых.
Хотя я полностью согласен с решением комитета, я действительно считаю, что использование несинхронизированного shared_ptr
типа в особых случаях дает определенные преимущества , поэтому я исследовал эту тему несколько раз.
Если я не использую несколько потоков или я использую несколько потоков, но не разделяю владение указателем между потоками, атомарный интеллектуальный указатель является излишним.
В GCC, когда ваша программа не использует несколько потоков, shared_ptr не использует атомарные операции для refcount. Это выполняется путем обновления счетчиков ссылок с помощью функций-оберток, которые определяют, является ли программа многопоточной (в GNU / Linux это делается просто путем определения, связана ли программа с libpthread.so
), и соответственно отправляют на атомарные или неатомарные операции.
Много лет назад я понял, что, поскольку GCC shared_ptr<T>
реализован в терминах __shared_ptr<T, _LockPolicy>
базового класса , можно использовать базовый класс с однопоточной политикой блокировки даже в многопоточном коде, явно используя __shared_ptr<T, __gnu_cxx::_S_single>
. К сожалению, поскольку это не было предполагаемым вариантом использования, он не работал оптимально до GCC 4.9, и некоторые операции по-прежнему использовали функции оболочки и поэтому отправлялись на атомарные операции, даже если вы явно запросили _S_single
политику. См. Пункт (2) на http://gcc.gnu.org/ml/libstdc++/2007-10/msg00180.html.для получения дополнительных сведений и исправления для GCC, позволяющего использовать неатомарную реализацию даже в многопоточных приложениях. Я сидел на этом патче много лет, но, наконец, сделал его для GCC 4.9, который позволяет вам использовать подобный шаблон псевдонима для определения типа общего указателя, который не является потокобезопасным, но работает немного быстрее:
template<typename T>
using shared_ptr_unsynchronized = std::__shared_ptr<T, __gnu_cxx::_S_single>;
Этот тип не будет взаимодействовать std::shared_ptr<T>
и будет безопасным в использовании только в том случае, если гарантируется, что shared_ptr_unsynchronized
объекты никогда не будут совместно использоваться потоками без дополнительной синхронизации, предоставляемой пользователем.
Это, конечно, совершенно непереносимо, но иногда это нормально. При правильном взломе препроцессора ваш код по-прежнему будет нормально работать с другими реализациями, если shared_ptr_unsynchronized<T>
это псевдоним shared_ptr<T>
, с GCC он будет немного быстрее.
Если вы используете GCC до 4.9, вы могли бы использовать это, добавив _Sp_counted_base<_S_single>
явные специализации в свой собственный код (и гарантируя, что никто никогда не будет создавать экземпляры __shared_ptr<T, _S_single>
без включения специализаций, чтобы избежать нарушений ODR). Добавление таких специализаций std
типов технически не определено, но будет работают на практике, потому что в этом случае нет никакой разницы между добавлением специализаций в GCC или их добавлением в ваш собственный код.