J'ai une fonction définie comme suit:
void foo(std::shared_ptr<X> x) { ... };
Si je déclare un ptr partagé à X
:
std::shared_ptr<X> sourcePtr(new X(...));
Je peux alors appeler foo
comme suit:
foo(std::move(sourcePtr));
ou
foo(sourcePtr);
Je comprends que si j'utilise la première option, sourcePtr
devient nul. Cela empêche-t-il également le nombre de références d'être incrémenté?
Si cela n'a pas d'importance, quelle option dois-je préférer? Dois-je envisager autre chose pour prendre une telle décision?
Oui, si vous déplacez le pointeur partagé dans la fonction, alors:
le sourcePtr
d'origine deviendra nul et
le nombre de références n'est pas modifié.
Si vous savez que vous n'aurez plus besoin de la valeur de sourcePtr
après l'appel de fonction, le déplacer dans la fonction est une légère optimisation, car il enregistre un atomic incrémentation (et décrémentation ultérieure, lorsque sourcePtr
sort du champ d'application).
Cependant, veillez à ce que l'identifiant sourcePtr
soit toujours valide pour le reste de la portée, juste qu'il contient un pointeur nul. Ce qui signifie que le compilateur ne se plaindra pas si vous l'utilisez après le déplacement, mais si vous oubliez qu'il a été déplacé, vous déréférerez très probablement le null. J'ai tendance à utiliser cette "optimisation" move
beaucoup, et j'ai également été mordu à plusieurs reprises: plus de fonctionnalités sont ajoutées à la fonction, et si vous oubliez d'annuler la move
, vous obtenez un joli crash.
Donc, bouger lorsque vous n'en avez plus besoin est une légère optimisation associée à une légère charge de maintenance. C'est à vous de peser ce qui est plus important dans votre cas.
Ce qui précède suppose qu'il existe du code qui utilise réellement sourcePtr
entre sa déclaration et l'appel final à foo
(merci à @WhozCraig de l'avoir signalé). Si ce n'est pas le cas, il serait beaucoup préférable de créer le pointeur directement sur le site de l'appel:
foo(std::make_shared<X>(...));
De cette façon, vous enregistrez la même quantité d'opérations atomiques, et vous n'avez pas de pointeur partagé vide potentiellement dangereux qui traîne.