Comment retourner des pointeurs intelligents (shared_ptr), par référence ou par valeur?
Disons que j'ai une classe avec une méthode qui retourne un shared_ptr
.
Quels sont les avantages et les inconvénients de nous le retourner par référence ou par valeur?
Deux indices possibles:
- Début de destruction des objets. Si je retourne la
shared_ptr
par (const) de référence, le compteur de référence n'est pas incrémenté, j'ai donc encourir le risque d'avoir l'objet supprimé quand elle est hors de portée dans un autre contexte (par exemple, un autre thread). Est-ce correct? Que faire si l'environnement est monothread, cette situation peut se produire aussi bien? - Coût. Passage par valeur est certainement pas gratuit. Est-ce la peine de l'éviter chaque fois que possible?
Merci tout le monde.
Vous devez vous connecter pour publier un commentaire.
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 à 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 la
shared_ptr
est tout simplement de retour par valeur: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:
cout << "Hello World!";
déclaration en défaut et le constructeur de copie, vous ne verrez pas deuxHello World!
s lors de la RVO est en vigueur. Toutefois, cela ne devrait pas être un problème pour bien conçu pointeurs intelligents, même w.r.t. la synchronisation.Concernant tout pointeur intelligent (pas seulement les shared_ptr), je ne pense pas que c'est jamais acceptable de retourner une référence à un, et je serais très hésitant à passer autour par la référence ou un pointeur brut. Pourquoi? Parce que vous ne pouvez pas être certain qu'il ne sera pas peu profonde copié par l'intermédiaire d'une référence plus tard. Votre premier point définit la raison pour laquelle cela devrait être un sujet de préoccupation. Cela peut se produire même dans un seul thread de l'environnement. Vous n'avez pas besoin d'un accès simultané aux données à mettre de la mauvaise copie de la sémantique dans vos programmes. Vous n'avez pas vraiment contrôler ce que vos utilisateurs à faire avec le pointeur une fois que vous passez le tout, afin de ne pas encourager l'utilisation abusive de donner à votre les utilisateurs de l'API assez de corde pour pendre eux-mêmes.
Deuxièmement, regardez votre smart pointeur de la mise en œuvre, si possible. De Construction et de destruction doit être sacrément près négligeable. Si cette surcharge n'est pas acceptable, ne pas utiliser un pointeur intelligent! Mais au-delà de cela, vous aurez également besoin d'examiner la simultanéité de l'architecture que vous avez, parce que mutuellement exclusifs l'accès au mécanisme qui suit les usages de l'pointeur va vous ralentir plus que la simple construction de la shared_ptr objet.
Modifier, 3 ans plus tard: avec l'avènement de la plus moderne des fonctions en C++, je voudrais peaufiner ma réponse à accepter des cas, quand vous avez tout simplement écrit un lambda qui ne vit à l'extérieur de l'appel de la fonction de la portée, et n'est pas copié quelque part d'autre. Ici, si vous souhaitez enregistrer la très surcharge minimale de la copie d'un pointeur partagé, il serait juste et sûr. Pourquoi? Parce que vous pouvez garantir que la référence ne sera jamais mal utilisée.