103 votes

En passant partagé des pointeurs comme arguments

Si je déclare un objet enveloppé dans un pointeur partagé:

std::shared_ptr<myClass> myClassObject(new myClass());

ensuite, j'ai voulu le passer en argument à une méthode:

DoSomething(myClassObject);

//the called method
void DoSomething(std::shared_ptr<myClass> arg1)
{
   arg1->someField = 4;
}

Le ci-dessus, il suffit d'incrémenter le shared_pt du nombre de références et tout est cool? Ou faut-il laisser un bancales pointeur?

Êtes-vous toujours censé faire ça?:

DoSomething(myClassObject.Get());

void DoSomething(std::shared_ptr<myClass>* arg1)
{
   (*arg1)->someField = 4;
}

Je pense que la 2ème façon peut-être plus efficace, car il n'a qu'à copier 1 adresse (par opposition à l'ensemble de pointeur intelligent), mais la 1ère méthode semble plus lisible et je ne m'attends pas à pousser les limites de la performance. Je veux juste m'assurer que il n'y a pas quelque chose de dangereux à ce sujet.

Je vous remercie.

186voto

R. Martinho Fernandes Points 96873

Je veux passer un pointeur partagé à une fonction. Dites-moi comment faire.

Je ne peux que penser à deux raisons de prendre un shared_ptr argument:

  1. La fonction veut partager la propriété de l'objet;
  2. La fonction effectue une opération qui travaille spécifiquement sur shared_ptrs.

Qui êtes-vous intéressé?

Je suis à la recherche d'une réponse d'ordre général, donc je suis vraiment intéressé à la fois. Je suis curieux de savoir ce que tu veux dire dans le cas n ° 2, si.

Des exemples de ces fonctions comprennent std::static_pointer_cast, personnalisé comparateurs, ou prédicats. Par exemple, si vous avez besoin de trouver tous uniques shared_ptr à partir d'un vecteur, vous avez besoin d'un tel prédicat.

Ah, quand la fonction les besoins de manipuler le pointeur intelligent lui-même.

Exactement.

Dans ce cas, je pense que nous devrions passer par référence.

Oui. Et si elle ne change pas le pointeur, vous voulez passer par référence const. Il n'y a pas besoin de copier puisque vous n'avez pas besoin de partager la propriété. C'est l'autre scénario.

Ok, l'a obtenu. Parlons un peu du scénario.

Celui où vous partagez la propriété? Ok. Comment voulez-vous partager la propriété avec des shared_ptr?

En le copiant.

Alors la fonction aurez besoin de faire une copie d'un shared_ptr, correct?

Évidemment. J'ai donc passer par une référence à const et copie d'une variable locale?

Non, c'est une pessimization. Si il est passé par référence, la fonction aura pas le choix de faire de la copie manuellement. Si il est passé par valeur, le compilateur choisir le meilleur choix entre une copie et un déplacer et effectuer automatiquement. Ainsi, le passage par valeur.

Bon point. Je dois me rappeler que "Veulent la Vitesse? Le passage par Valeur." l'article le plus souvent.

Attendez, si la fonction stocke l' shared_ptr dans une variable de membre, par exemple? Ne sera pas que faire une copie redondante?

La fonction peut simplement déplacer l' shared_ptr argument en sa mémoire. Le déplacement d'un shared_ptr n'est pas cher parce qu'il n'est pas prêt de changer le nombre de références.

Ah, bonne idée.

Mais je pense à un troisième scénario: que faire si vous ne voulez pas manipuler l' shared_ptr, ni à la détention d'actions?

Dans ce cas, shared_ptr est totalement indifférent à la fonction. Si vous souhaitez manipuler les pointee, prendre un pointee, et de laisser les appelants de choisir quelle sémantique de propriété qu'ils veulent.

Et dois-je prendre le pointee par référence ou par valeur?

Les règles habituelles s'appliquent. Les pointeurs intelligents de ne pas changer quoi que ce soit.

Le passage par valeur si je vais copier, passage par référence si je veux éviter une copie.

La droite.

Hmm. Je crois que vous avez oublié encore un autre scénario. Que faire si je veux partager la propriété, mais seulement en fonction d'un certain état?

Ah, un intéressant cas de bord. Je n'attends pas que cela arrive souvent. Mais quand il arrive, vous pouvez passer soit par valeur et d'ignorer la copie si vous n'en avez pas besoin, ou de passer par renvoi et en faire une copie si vous en avez besoin.

Je risque une copie redondante dans la première option, et de perdre un potentiel de se déplacer dans la seconde. Je ne peux pas manger le gâteau et l'avoir aussi?

Si vous êtes dans une situation où ce qui importe vraiment, vous pouvez fournir deux surcharges, l'un prenant un const lvalue de référence, et de l'autre la prise de référence rvalue. L'un des exemplaires, l'autre se déplace. Un parfait transfert de modèle de fonction est une autre option.

Je pense que tous les scénarios possibles. Je vous remercie beaucoup.

29voto

Mark Ransom Points 132545

Je pense que les gens sont inutilement peur de raw à l'aide de pointeurs comme paramètres de la fonction. Si la fonction ne va pas stocker le pointeur ou autrement affecter sa durée de vie, un pointeur brut fonctionne tout aussi bien et représente le plus petit dénominateur commun. Considérons par exemple la façon dont vous voulez passer un unique_ptr dans une fonction qui prend un shared_ptr comme paramètre par valeur ou par référence const?

void DoSomething(myClass * p);

DoSomething(myClass_shared_ptr.get());
DoSomething(myClass_unique_ptr.get());

Un pointeur brut comme paramètre d'une fonction ne vous empêche pas d'utiliser des pointeurs intelligents dans le code appelant, là où cela compte vraiment.

5voto

R Samuel Klatchko Points 44549

Oui, l'idée entière sur un shared_ptr<>, c'est que plusieurs instances peuvent contenir la même pointeur brut et de la mémoire sous-jacente ne seront libérés quand il ya la dernière instance de shared_ptr<> est détruit.

Je voudrais éviter un pointeur vers un shared_ptr<> que cela va à l'encontre du but que vous êtes maintenant affaire avec raw_pointers de nouveau.

2voto

djechlin Points 18051

Passage par valeur dans votre premier exemple est sûr, mais il y a une meilleure idiome. Passage par référence const lorsque c'est possible - je dirais que oui, même lorsque vous traitez avec des pointeurs intelligents. Votre deuxième exemple n'est pas exactement brisée, mais il est très - !???. Stupide, de ne pas accomplir quelque chose et de défaites partie du point de pointeurs intelligents, et va vous laisser dans un buggy monde de la douleur lorsque vous essayez de déréférencement et de modifier les choses.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X