Howard ha già risposto bene alla domanda e Nicol ha sottolineato alcuni buoni punti sui vantaggi di avere un singolo tipo di puntatore condiviso standard, piuttosto che molti tipi incompatibili.
Anche se sono completamente d'accordo con la decisione del comitato, penso che ci sia qualche vantaggio nell'usare un shared_ptr
tipo non sincronizzato in casi speciali , quindi ho esaminato l'argomento alcune volte.
Se non sto utilizzando più thread o se sto utilizzando più thread ma non condivido la proprietà del puntatore tra i thread, un puntatore intelligente atomico è eccessivo.
Con GCC quando il tuo programma non utilizza più thread shared_ptr non usa operazioni atomiche per il refcount. Questo viene fatto aggiornando i conteggi dei riferimenti tramite funzioni wrapper che rilevano se il programma è multithread (su GNU / Linux questo viene fatto semplicemente rilevando se il programma si collega a libpthread.so
) e invia di conseguenza a operazioni atomiche o non atomiche.
Mi sono reso conto molti anni fa che poiché GCC shared_ptr<T>
è implementato in termini di una __shared_ptr<T, _LockPolicy>
classe base , è possibile utilizzare la classe base con la politica di blocco a thread singolo anche in codice multithread, utilizzando esplicitamente __shared_ptr<T, __gnu_cxx::_S_single>
. Sfortunatamente, poiché non era un caso d'uso previsto, non funzionava in modo ottimale prima di GCC 4.9 e alcune operazioni utilizzavano ancora le funzioni wrapper e quindi inviate alle operazioni atomiche anche se hai esplicitamente richiesto la _S_single
politica. Vedere il punto (2) su http://gcc.gnu.org/ml/libstdc++/2007-10/msg00180.htmlper maggiori dettagli e una patch a GCC per consentire l'utilizzo dell'implementazione non atomica anche nelle app multithread. Mi sono seduto su quella patch per anni, ma alla fine l'ho impegnata per GCC 4.9, che ti consente di utilizzare un modello di alias come questo per definire un tipo di puntatore condiviso che non è thread-safe, ma è leggermente più veloce:
template<typename T>
using shared_ptr_unsynchronized = std::__shared_ptr<T, __gnu_cxx::_S_single>;
Questo tipo non sarebbe interoperabile std::shared_ptr<T>
e sarebbe sicuro da usare solo quando è garantito che gli shared_ptr_unsynchronized
oggetti non sarebbero mai condivisi tra i thread senza un'ulteriore sincronizzazione fornita dall'utente.
Questo è ovviamente completamente non portatile, ma a volte va bene. Con gli hack del preprocessore giusti il tuo codice funzionerebbe ancora bene con altre implementazioni se shared_ptr_unsynchronized<T>
è un alias per shared_ptr<T>
, sarebbe solo un po 'più veloce con GCC.
Se stai utilizzando un GCC prima della 4.9, potresti usarlo aggiungendo le _Sp_counted_base<_S_single>
specializzazioni esplicite al tuo codice (e assicurandoti che nessuno crei mai istanze __shared_ptr<T, _S_single>
senza includere le specializzazioni, per evitare violazioni ODR). L'aggiunta di tali specializzazioni di std
tipi è tecnicamente indefinita, ma lo sarebbe funziona in pratica, perché in questo caso non c'è differenza tra me che aggiungo le specializzazioni a GCC o che tu le aggiungi al tuo codice.