Howard já respondeu bem à pergunta e Nicol fez alguns bons pontos sobre os benefícios de ter um único tipo de ponteiro compartilhado padrão, em vez de muitos tipos incompatíveis.
Embora eu concorde totalmente com a decisão do comitê, acho que há algum benefício em usar um shared_ptr
tipo do tipo não sincronizado em casos especiais , então investiguei o tópico algumas vezes.
Se eu não estiver usando vários threads, ou se eu estiver usando vários threads, mas não estou compartilhando a propriedade do ponteiro entre os threads, um ponteiro inteligente atômico é um exagero.
Com o GCC, quando o seu programa não usa vários threads, shared_ptr não usa ops atômicos para o refcount. Isso é feito atualizando as contagens de referência por meio de funções de wrapper que detectam se o programa é multithreaded (no GNU / Linux isso é feito simplesmente detectando se o programa está vinculado alibpthread.so
) e despacha para operações atômicas ou não atômicas de acordo.
Percebi há muitos anos que, como o GCC shared_ptr<T>
é implementado em termos de uma __shared_ptr<T, _LockPolicy>
classe base , é possível usar a classe base com a política de bloqueio de thread único, mesmo em código multithread, usando explicitamente __shared_ptr<T, __gnu_cxx::_S_single>
. Infelizmente, como esse não era um caso de uso pretendido, não funcionava perfeitamente antes do GCC 4.9, e algumas operações ainda usavam as funções de wrapper e, portanto, despachavam para operações atômicas, embora você tenha solicitado explicitamente a _S_single
política. Veja o ponto (2) em http://gcc.gnu.org/ml/libstdc++/2007-10/msg00180.htmlpara obter mais detalhes e um patch para o GCC para permitir que a implementação não atômica seja usada mesmo em aplicativos multithread. Fiquei sentado naquele patch por anos, mas finalmente o comprometi para o GCC 4.9, que permite usar um modelo de alias como este para definir um tipo de ponteiro compartilhado que não é seguro para thread, mas é um pouco mais rápido:
template<typename T>
using shared_ptr_unsynchronized = std::__shared_ptr<T, __gnu_cxx::_S_single>;
Este tipo não seria interoperável com std::shared_ptr<T>
e somente seria seguro para uso quando fosse garantido que os shared_ptr_unsynchronized
objetos nunca seriam compartilhados entre threads sem sincronização adicional fornecida pelo usuário.
É claro que isso é completamente não portável, mas às vezes não tem problema. Com os hacks de pré-processador corretos, seu código ainda funcionaria bem com outras implementações, se shared_ptr_unsynchronized<T>
fosse um apelido para shared_ptr<T>
, seria um pouco mais rápido com o GCC.
Se você estiver usando um GCC anterior ao 4.9, poderá usá-lo adicionando as _Sp_counted_base<_S_single>
especializações explícitas ao seu próprio código (e garantindo que ninguém instancie __shared_ptr<T, _S_single>
sem incluir as especializações, para evitar violações de ODR.) Adicionar essas especializações de std
tipos é tecnicamente indefinido, mas seria funcionam na prática, porque neste caso não há diferença entre eu adicionar as especializações ao GCC ou você adicioná-las ao seu próprio código.