Le monde dans lequel vit Bjarne est très ... académique, faute d'un meilleur terme. Si votre code peut être conçu et structuré de manière à ce que les objets aient des hiérarchies relationnelles très délibérées, de sorte que les relations de propriété soient rigides et inflexibles, le code circule dans un sens (du plus bas au plus bas), et les objets ne parlent qu'aux plus bas. la hiérarchie, alors vous ne trouverez pas beaucoup besoin shared_ptr
. C'est quelque chose que vous utilisez dans les rares occasions où quelqu'un doit enfreindre les règles. Mais sinon, vous pouvez simplement coller tout ce qui est dans vector
s ou dans d'autres structures de données qui utilisent la sémantique de valeur, et unique_ptr
s pour les choses que vous devez allouer individuellement.
C'est un monde où il fait bon vivre, mais ce n'est pas ce que vous devez faire tout le temps. Si vous ne pouvez pas organiser votre code de cette manière, car la conception du système que vous essayez de créer signifie qu'il est impossible (ou tout simplement profondément déplaisant), vous allez alors vous retrouver de plus en plus confronté à la propriété partagée des objets. .
Dans un tel système, tenir des pointeurs nus n’est pas… dangereux, mais cela soulève des questions. L'avantage shared_ptr
est qu'il fournit des garanties syntaxiques raisonnables sur la durée de vie de l'objet. Peut-il être cassé? Bien sûr. Mais les gens peuvent aussi des const_cast
choses; les soins de base et l'alimentation des enfants shared_ptr
devraient fournir une qualité de vie raisonnable aux objets attribués dont la propriété doit être partagée.
Ensuite, il y a weak_ptr
s, qui ne peuvent pas être utilisés en l'absence de shared_ptr
. Si votre système est structuré de manière rigide, vous pouvez stocker un pointeur nu sur un objet, en sachant que la structure de l'application garantit que l'objet pointé vous survivra. Vous pouvez appeler une fonction qui renvoie un pointeur sur une valeur interne ou externe (recherchez un objet nommé X, par exemple). Dans un code correctement structuré, cette fonction ne serait disponible que si la durée de vie de l'objet était supérieure à la votre; ainsi, stocker ce pointeur nu dans votre objet est très bien.
Étant donné que cette rigidité n’est pas toujours possible dans les systèmes réels, vous avez besoin d’un moyen raisonnable d’en assurer la durée de vie. Parfois, vous n'avez pas besoin de la pleine propriété. Parfois, il suffit de savoir quand le pointeur est mauvais ou bon. C’est là que l’ weak_ptr
intervient. Dans certains cas, j’aurais pu utiliser un unique_ptr
ou boost::scoped_ptr
, mais je devais utiliser un shared_ptr
parce que j’avais précisément besoin de donner à quelqu'un un pointeur "volatil". Un pointeur dont la durée de vie était indéterminée, et ils pouvaient demander quand ce pointeur avait été détruit.
Un moyen sûr de survivre lorsque l'état du monde est indéterminé.
Cela aurait-il pu être fait par un appel de fonction pour obtenir le pointeur, au lieu de via weak_ptr
? Oui, mais cela pourrait être plus facilement cassé. Une fonction qui retourne un pointeur nu n'a aucun moyen de suggérer syntaxiquement que l'utilisateur ne fasse pas quelque chose comme stocker ce pointeur à long terme. Le renvoi d'un shared_ptr
rend également beaucoup trop facile pour quelqu'un de simplement le stocker et potentiellement prolonger la durée de vie d'un objet. Restituer un weak_ptr
message suggère toutefois fortement que le stockage de ce que shared_ptr
vous obtenez lock
est une idée ... douteuse. Cela ne vous empêchera pas de le faire, mais rien en C ++ ne vous empêchera de casser du code. weak_ptr
fournit une résistance minimale de faire la chose naturelle.
Maintenant, cela shared_ptr
ne veut pas dire que vous ne pouvez pas en abuser ; cela peut certainement. Surtout avant unique_ptr
, il y avait beaucoup de cas où j'ai simplement utilisé un boost::shared_ptr
parce que je devais passer un pointeur RAII ou le mettre dans une liste. Sans la sémantique de mouvement et unique_ptr
, boost::shared_ptr
était la seule vraie solution.
Et vous pouvez l'utiliser dans des endroits où cela est vraiment inutile. Comme indiqué ci-dessus, une structure de code appropriée peut éliminer le besoin de certaines utilisations de shared_ptr
. Mais si votre système ne peut pas être structuré en tant que tel et continue à faire ce qu’il faut, shared_ptr
il sera d’une grande utilité.