Howard a déjà bien répondu à la question, et Nicol a souligné les avantages d'avoir un seul type de pointeur partagé standard, plutôt que beaucoup de types incompatibles.
Bien que je sois entièrement d'accord avec la décision du comité, je pense qu'il y a un certain avantage à utiliser un shared_ptr
type non synchronisé dans des cas particuliers . J'ai donc étudié le sujet à quelques reprises.
Si je n'utilise pas plusieurs threads, ou si j'utilise plusieurs threads mais que je ne partage pas la propriété du pointeur entre les threads, un pointeur intelligent atomique est excessif.
Avec GCC lorsque votre programme n'utilise pas plusieurs threads shared_ptr n'utilise pas d'opérations atomiques pour le refcount. Cela se fait en mettant à jour le nombre de références via des fonctions wrapper qui détectent si le programme est multithread (sous GNU / Linux, cela se fait simplement en détectant si le programme est lié à libpthread.so
) et en les distribuant aux opérations atomiques ou non atomiques en conséquence.
J'ai réalisé il y a de nombreuses années que parce que GCC shared_ptr<T>
est implémenté en termes de __shared_ptr<T, _LockPolicy>
classe de base , il est possible d'utiliser la classe de base avec la politique de verrouillage monothread même dans le code multithread, en utilisant explicitement __shared_ptr<T, __gnu_cxx::_S_single>
. Malheureusement, comme ce n'était pas un cas d'utilisation prévu, cela ne fonctionnait pas de manière optimale avant GCC 4.9, et certaines opérations utilisaient toujours les fonctions wrapper et étaient donc distribuées aux opérations atomiques même si vous avez explicitement demandé la _S_single
politique. Voir le point (2) sur http://gcc.gnu.org/ml/libstdc++/2007-10/msg00180.htmlpour plus de détails et un correctif pour GCC pour permettre à l'implémentation non atomique d'être utilisée même dans les applications multithread. Je me suis assis sur ce patch pendant des années, mais je l'ai finalement validé pour GCC 4.9, qui vous permet d'utiliser un modèle d'alias comme celui-ci pour définir un type de pointeur partagé qui n'est pas thread-safe, mais qui est légèrement plus rapide:
template<typename T>
using shared_ptr_unsynchronized = std::__shared_ptr<T, __gnu_cxx::_S_single>;
Ce type ne serait pas interopérable avec std::shared_ptr<T>
et ne serait sûr à utiliser que s'il est garanti que les shared_ptr_unsynchronized
objets ne seront jamais partagés entre les threads sans une synchronisation supplémentaire fournie par l'utilisateur.
C'est bien sûr complètement non portable, mais parfois c'est OK. Avec les bons hacks de préprocesseur, votre code fonctionnera toujours bien avec d'autres implémentations si shared_ptr_unsynchronized<T>
c'est un alias pour shared_ptr<T>
, ce serait juste un peu plus rapide avec GCC.
Si vous utilisez un GCC antérieur à 4.9, vous pouvez l'utiliser en ajoutant les _Sp_counted_base<_S_single>
spécialisations explicites à votre propre code (et en vous assurant que personne n'instancie jamais __shared_ptr<T, _S_single>
sans inclure les spécialisations, pour éviter les violations ODR.) L'ajout de telles spécialisations de std
types est techniquement indéfini, mais le ferait travailler dans la pratique, car dans ce cas, il n'y a aucune différence entre moi ajoutant les spécialisations à GCC ou vous les ajoutant à votre propre code.