Question

Quels sont les avantages de passer d'un pointeur à l'autre en passant par une référence en C ++?

Dernièrement, j'ai vu un certain nombre d'exemples qui ont choisi de passer des arguments de fonction par des pointeurs au lieu de passer par référence. Y a-t-il des avantages à le faire?

Exemple:

func(SPRITE *x);

avec un appel de

func(&mySprite);

vs.

func(SPRITE &x);

avec un appel de

func(mySprite);
Était-ce utile?

La solution

Un pointeur peut recevoir un paramètre NULL, un paramètre de référence ne peut pas. Si vous avez toujours la possibilité de laisser passer "pas d'objet", utilisez un pointeur au lieu d'une référence.

De plus, passer par un pointeur vous permet de voir explicitement sur le site de l'appel si l'objet est passé par valeur ou par référence:

// Is mySprite passed by value or by reference?  You can't tell 
// without looking at the definition of func()
func(mySprite);

// func2 passes "by pointer" - no need to look up function definition
func2(&mySprite);

Autres conseils

En passant par le pointeur

  • L'appelant doit prendre l'adresse - > pas transparent
  • Une valeur 0 peut être fournie pour signifier rien . Ceci peut être utilisé pour fournir des arguments optionnels.

Passer par référence

  • L'appelant passe simplement l'objet - > transparent. Doit être utilisé pour la surcharge de l'opérateur, car la surcharge pour les types de pointeur n'est pas possible (les pointeurs sont des types intégrés). Vous ne pouvez donc pas utiliser chaîne s = & amp; str1 + & str2; en utilisant des pointeurs.
  • Pas de 0 valeurs possibles - > La fonction appelée n'a pas à les vérifier
  • La référence à const accepte également les temporaires: void f (const T & amp; t); ... f (T (a, b, c)); , les pointeurs ne peuvent pas être utilisés de cette façon, car vous ne pouvez pas prendre l’adresse d’un temporaire.
  • Enfin, les références sont plus faciles à utiliser - > moins de chance pour les bugs.

Allen Holub "Assez de corde pour se tirer une balle dans le pied" répertorie les 2 règles suivantes:

120. Reference arguments should always be `const`
121. Never use references as outputs, use pointers

Il répertorie plusieurs raisons pour lesquelles des références ont été ajoutées à C ++:

  • ils sont nécessaires pour définir les constructeurs de copie
  • ils sont nécessaires pour les surcharges d’opérateurs
  • Les références
  • const vous permettent d'avoir une sémantique pas à pas tout en évitant la copie

Son point essentiel est que les références ne doivent pas être utilisées en tant que paramètres de "sortie" car sur le site de l'appel, il n'est pas indiqué si le paramètre est une référence ou une valeur. Sa règle est donc de n'utiliser que des références const .

Personnellement, je pense que ceci est une bonne règle empirique, car cela le rend plus clair lorsqu'un paramètre est un paramètre de sortie ou non. Cependant, même si je suis personnellement d’accord avec cela en général, je me permets d’être influencé par les opinions des autres membres de mon équipe s’ils défendent les paramètres de sortie comme références (certains développeurs les apprécient immensément).

J'aime le raisonnement tiré d'un article de "cplusplus.com:"

.
  
      
  1. Pass by value lorsque la fonction ne veut pas modifier le paramètre et que la valeur est facile à copier (types, double, char, bool, etc ... types simples. std :: string, std :: vecteur, et tous les autres conteneurs STL ne sont PAS des types simples.)

  2.   
  3. Pointeur de passage par const lorsque la valeur coûte cher à copier ET la fonction ne veut pas modifier la valeur pointée vers AND NULL est une valeur attendue valide que la fonction gère.

  4.   
  5. Passer par le pointeur non-const lorsque la valeur coûte cher à copier ET la fonction veut modifier la valeur pointée vers AND NULL est une valeur attendue valide que la fonction gère.

  6.   
  7. Passer par référence const lorsque la valeur est chère à copier ET la fonction ne veut pas modifier la valeur mentionnée AND NULL ne serait pas une valeur valide si un pointeur était utilisé à la place.

  8.   
  9. Passer par une référence non-cont lorsque la valeur coûte cher à copier ET la fonction veut modifier la valeur référencée ET NULL ne serait pas une valeur valide si un pointeur était utilisé à la place.

  10.   
  11. Lors de la rédaction de fonctions de modèle, il n'y a pas de réponse claire, car il existe quelques compromis à prendre en compte qui dépassent le cadre de la présente discussion, mais il suffit de dire que la plupart des fonctions de modèle prennent en compte leurs paramètres. Cependant, comme la syntaxe des itérateurs est similaire à celle des pointeurs (astérisque de "déréférencement"), toute fonction de modèle qui attend des itérateurs comme arguments acceptera également par défaut les pointeurs (et ne vérifie pas la valeur NULL, Le concept itérateur NULL a une syntaxe différente).

  12.   
     

http://www.cplusplus.com/articles/z6vU7k9E/

Ce que je retiens de ceci, c’est que la principale différence entre choisir d’utiliser un pointeur ou un paramètre de référence est si NULL est une valeur acceptable. C'est ça.

Après tout, que la valeur soit entrée, sortie, modifiable, etc. devrait être dans la documentation / les commentaires sur la fonction.

Précisions sur les articles précédents:

Les références constituent PAS le gage d'obtenir un pointeur non null. (Bien que nous les traitions souvent comme tels.)

Bien que le code soit horriblement mauvais, comme pour vous sortir du code mauvais de Woodshed, ce qui suit va compiler & amp; run: (au moins sous mon compilateur.)

bool test( int & a)
{
  return (&a) == (int *) NULL;
}

int
main()
{
  int * i = (int *)NULL;
  cout << ( test(*i) ) << endl;
};

Le vrai problème que j'ai avec les références réside dans les autres programmeurs, désormais nommés IDIOTS , qui allouent dans le constructeur, libèrent dans le destructeur, . et ne pas fournir un constructeur de copie ou un opérateur = ().

Tout à coup, il y a un monde de différence entre foo (BAR bar) et foo (BAR & amp; bar) . (L'opération de copie au niveau du bit automatique est invoquée. La déviation dans le destructeur est invoquée deux fois.)

Heureusement, les compilateurs modernes prendront en compte cette double désallocation du même pointeur. Il y a 15 ans, ils ne l'ont pas fait. (Sous gcc / g ++, utilisez setenvMALLOC_CHECK_ 0 pour revoir les anciennes méthodes.) Résultat, sous DEC UNIX, la même mémoire étant allouée à deux objets différents. Beaucoup de plaisir à déboguer là-bas ...

Plus concrètement:

  • Les références masquent le fait que vous modifiez les données stockées ailleurs.
  • Il est facile de confondre une référence avec un objet copié.
  • Les pointeurs rendent cela évident!

Pas vraiment. En interne, le passage par référence est effectué en transmettant essentiellement l'adresse de l'objet référencé. Donc, il n’ya vraiment aucun gain d’efficacité à obtenir en passant un pointeur.

Passer par référence présente toutefois un avantage. Vous avez la garantie d'avoir une instance de tout type d'objet / type en cours de transmission. Si vous passez un pointeur, vous courez le risque de recevoir un pointeur NULL. En utilisant la méthode de référence par référence, vous transmettez à l'appelant de votre fonction un contrôle NULL implicite d'un niveau supérieur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top