De retour des pointeurs intelligents en valeur.
Comme vous l'avez dit, si vous le retourner par référence, vous n'aurez pas correctement incrémenter le compteur de référence, ce qui ouvre le risque de la suppression de quelque chose à la mauvaise heure. Rien que cela devrait être une raison suffisante pour ne pas retourner par référence. Les Interfaces doivent être robustes.
Le coût préoccupation est aujourd'hui discutable, grâce à la valeur de retour d'optimisation (RVO), de sorte que vous n'aurez pas à supporter un incrément incrément-décrémentation de la séquence ou quelque chose comme ça dans les compilateurs modernes. Donc, la meilleure façon de rétablir shared_ptr
est de simplement retourner par valeur:
shared_ptr<T> Foo()
{
return shared_ptr<T>(/* acquire something */);
};
C'est une mort évidente RVO occasion pour moderne compilateurs C++. Je sais pour un fait que Visual C++ compilateurs mettre en œuvre RVO même lorsque toutes les optimisations sont éteints. Et avec C++11 de la sémantique de déplacement, elle l'est encore moins pertinent. (Mais la seule façon d'en être sûr est de profil et de l'expérience.)
Si vous n'êtes toujours pas convaincu, Dave Abrahams a un article qui fait un argument pour le retour par valeur. Je reproduis un extrait ici; je vous recommande fortement d'aller lire l'article en entier:
Être honnête: comment fonctionne le code suivant vous faire sentir?
std::vector<std::string> get_names();
...
std::vector<std::string> const names = get_names();
Franchement, même si je devrais le savoir mieux, ça me rend nerveux. En principe, lorsqu' get_names()
les retours, nous avons pour copier un vector
de string
s. Ensuite, nous avons besoin de le copier à nouveau lorsque nous initialisons
names
, et nous avons besoin de détruire la première copie. S'il y a N string
s dans le vecteur, chaque copie
pourrait exiger autant que le N+1 les allocations de mémoire et une flopée de cache-hostiles accès de données > comme le contenu de la chaîne sont copiés.
Plutôt que d'affronter ce genre d'angoisse, je suis souvent tombé en arrière sur le laisser-passer-par-référence afin d'éviter
inutile de copies:
get_names(std::vector<std::string>& out_param );
...
std::vector<std::string> names;
get_names( names );
Malheureusement, cette approche est loin d'être idéale.
- Le code a augmenté de 150%
- Nous avons dû abandonner
const
-ness parce que nous sommes une mutation des noms.
- Aussi fonctionnelle des programmeurs comme pour nous rappeler, la mutation rend le code plus complexe à raison à propos de saper la transparence référentielle et général paramétré par le raisonnement.
- Nous n'avons plus stricte de la valeur sémantique des noms.
Mais est-il vraiment nécessaire de gâcher notre code dans ce sens afin de gagner en efficacité? Heureusement, la réponse s'avère être pas (et surtout pas si vous êtes à l'aide de C++0x).