Sydius a assez bien décrit les types :
-
Pointeurs normaux sont juste ça - ils pointent vers quelque chose dans la mémoire quelque part. Qui en est le propriétaire ? Seuls les commentaires vous le diront. Qui le libère ? Le propriétaire, espérons-le, à un moment donné.
-
Pointeurs intelligents sont un terme générique qui couvre de nombreux types ; je suppose que vous vouliez parler de pointeur scopé, qui utilise la fonction RAII modèle. C'est un objet alloué par la pile qui enveloppe un pointeur ; lorsqu'il sort de sa portée, il appelle delete sur le pointeur qu'il enveloppe. Il "possède" le pointeur contenu dans la mesure où il est chargé de le supprimer à un moment donné. Ils vous permettent d'obtenir une référence brute au pointeur qu'ils enveloppent pour le transmettre à d'autres méthodes, ainsi que de libérant le pointeur, permettant à quelqu'un d'autre de le posséder. Les copier n'a pas de sens.
-
Pointeurs partagés est un objet alloué par la pile qui enveloppe un pointeur de façon à ce que vous n'ayez pas à savoir qui en est le propriétaire. Lorsque le dernier pointeur partagé d'un objet en mémoire est détruit, le pointeur enveloppé est également supprimé.
Et quand faut-il les utiliser ? Vous ferez un usage intensif des pointeurs scopés ou des pointeurs partagés. Combien de threads sont en cours d'exécution dans votre application ? Si la réponse est "potentiellement beaucoup", les pointeurs partagés peuvent s'avérer être un goulot d'étranglement des performances s'ils sont utilisés partout. La raison en est que la création/copie/destruction d'un pointeur partagé doit être une opération atomique, ce qui peut nuire aux performances si vous avez de nombreux threads en cours d'exécution. Cependant, ce ne sera pas toujours le cas - seuls les tests vous le diront avec certitude.
Il y a un argument (que j'aime bien) contre les pointeurs partagés - en les utilisant, vous permettez aux programmeurs d'ignorer qui possède un pointeur. Cela peut conduire à des situations délicates avec des références circulaires (Java les détecte, mais pas les pointeurs partagés) ou à la paresse générale des programmeurs dans une grande base de code.
Il y a deux raisons d'utiliser les pointeurs scopés. La première est pour la sécurité des exceptions simples et les opérations de nettoyage - si vous voulez garantir qu'un objet est nettoyé quoi qu'il arrive face aux exceptions, et que vous ne voulez pas allouer cet objet en pile, mettez-le dans un pointeur scoped. Si l'opération est un succès, vous pouvez le transférer sur un pointeur partagé, mais en attendant, économisez l'overhead avec un pointeur scopé.
L'autre cas est celui où l'on veut une propriété claire des objets. Certaines équipes préfèrent cela, d'autres non. Par exemple, une structure de données peut renvoyer des pointeurs vers des objets internes. Avec un pointeur scopé, elle renvoie un pointeur brut ou une référence qui doit être traitée comme une référence faible - c'est une erreur d'accéder à ce pointeur après que la structure de données qui le possède ait été détruite, et c'est une erreur de le supprimer. Dans le cas d'un pointeur partagé, l'objet propriétaire ne peut pas détruire les données internes qu'il a renvoyées si quelqu'un détient toujours un handle dessus - cela pourrait laisser des ressources ouvertes pendant beaucoup plus longtemps que nécessaire, ou bien pire selon le code.