7
votes

Passer un paramètre modifiable à la fonction C ++

fourni, je veux transmettre un paramètre modifiable sur une fonction, que dois-je choisir: pour le transmettre par le pointeur ou le transmettre par référence?

  1. bool getfoo (foo & whéretoplaceresult);
  2. bool getfoo (foo * whéretoplaceresult);

    Je le demande parce que je considérais toujours la meilleure pratique de passer le paramètre par référence (1), mais après avoir examiné une base de données de code locale, je suis arrivé à une conclusion que la manière la plus courante est (2). De plus, l'homme lui-même (Bjarne Stroustrup) recommande d'utiliser (2). Quels sont les avantages [DIS] de (1) et (2), ou est-ce juste une question de goût personnel?


4 commentaires

Avez-vous une référence pour STROSTRUP recommandant 2? Je semble me rappeler le contraire.


Comme Stroustrup dit, GetFoo (& Data) est plus évident que GetFoo (données), si la fonction doit modifier la valeur des données. Je trouverai la citation exacte plus tard aujourd'hui ...


STROSTRUP le recommande dans le livre TC ++ PL.


Je l'ai maintenant. "Le langage de programmation C ++", section 5.5 dit: "Pour rendre le programme plus lisible, vous devriez éviter les fonctions, modifier leurs arguments. Vous devez préférer les fonctions, renvoyer des valeurs ou passer des pointeurs comme des paramètres de fonction". Désolé, mon livre est en russe et je dois traduire au lieu de donner la citation directe ...


12 Réponses :


22
votes

Je préfère une référence au lieu d'un pointeur lorsque:

  • Il ne peut pas être null
  • On ne peut pas être changé (pour pointer vers quelque chose d'autre)
  • Il ne faut pas être supprimé (par qui reçoit le pointeur)

    Certaines personnes disent que la différence entre une référence et une référence de const est trop subtile pour de nombreuses personnes et est invisible dans le code qui appelle la méthode (c'est-à-dire si vous lisez le code d'appel qui transmet un paramètre par référence, Vous ne pouvez pas voir s'il s'agit d'une référence de const ou de non-Const) et que vous devriez donc en faire un pointeur (pour le rendre explicite dans le code d'appel que vous donnez l'adresse de votre variable et que donc La valeur de votre variable peut être modifiée par la callee).

    Je préfère personnellement une référence, pour la raison suivante:

    1. Je pense qu'une routine devrait savoir quel sous-programme il appelle
    2. Un sous-programme ne devrait rien assumer de quelle routine à laquelle il est appelé.

      [1. 1. / p>

      [2. 2.] implique que si c'est un pointeur, le sous-programme doit gérer la possibilité que le paramètre est un pointeur NULL, qui peut être un code supplémentaire et un code inutile.

      En outre, chaque fois que je vois un pointeur, je pense, "qui va supprimer cela, et quand?", Donc, chaque fois que la propriété / la vie / la durée de vie / la suppression n'est pas un problème que je préfère utiliser une référence.

      Pour ce que ça vaut la peine, j'ai l'habitude d'écrire Const-Code Code: Donc, si je déclare qu'une méthode a un paramètre de référence non-Const, le fait que c'est non-constitué est significatif. Si les gens n'écrivaient pas le code Cons-Correct, il serait peut-être plus difficile de dire si un paramètre sera modifié dans un sous-programme et que l'argument d'un autre mécanisme (par exemple, un pointeur au lieu d'une référence) serait un peu plus fort. < / p>


3 commentaires

Les pointeurs passés dans une méthode ne peuvent pas être changés pour pointer ailleurs.


@Lou - c'est vrai; Ou du moins, il peut-il changer peut-être changé, mais ce changement ne serait pas affecter l'appelant (c'est-à-dire que la callee modifierait la valeur de la copie locale de la callee du pointeur).


@LOU, la copie locale du pointeur peut, et parfois, a changé. Cela traduit souvent les débutants qui pensent que le pointeur de l'appelant est maintenant changé aussi. Une autre raison de rester à l'écart du n ° 2 (ou du moins d'éviter de modifier des arguments de pointeur) IMHO.



1
votes

Je choisis # 2 car il est évident au point d'appel que le paramètre sera changé.

getfoo (& var) plutôt que getfoo (var)

Je préfère passer par référence pour juste des références de const, où j'essaie d'éviter un appel de constructeur de copie.


0 commentaires

0
votes

Il semble que je me souvienne de rappeler que dans les références C ++ où ne sont pas nuls et que des pointeurs pouvaient être. Maintenant, je n'ai pas fait C ++ pendant une longue période pour que ma mémoire puisse être rouillée.


0 commentaires

4
votes

Un avantage à passer par référence est qu'ils ne peuvent pas être nuls (différents pointeurs), en empêchant la nécessité de vérifier tous les paramètres de sortie.


1 commentaires

Getfoo ( (foo ) 0); Et tout getfoo (* PTR); d'ailleurs. Cela ne dépend pas de la manière dont le paramètre est accepté, mais plutôt comment il est passé. Je pense que cité Stroustrup (réelle ou fausse) a du sens - lorsque vous utilisez le pointeur est plus évident. D'autre part, je pense qu'il est préférable de décider sur place de quelle manière vous voulez aller dans le cas particulier.



1
votes

passe par référence et évitez tout problème de pointeur NULL.


0 commentaires

0
votes

La différence ici est relativement mineure.

Une référence ne peut pas être nulle.

Un nullpointer peut être passé. Ainsi, vous pouvez vérifier si cela se produit et réagir en conséquence.

Personnellement, je ne peux pas penser à un véritable avantage de l'une des deux possibilités.


1 commentaires

Pour un, je ne considère pas cette différence "mineure" - c'est la différence entre un objet et aucun objet, après tout. En outre, il existe une autre différence: un pointeur peut facilement être invalide (point à une adresse aléatoire), tandis qu'une référence ne peut pas être facilement invalide.



0
votes

Je trouve cela une question de goût personnel. En fait, je préfère passer par référence parce que les pointeurs donnent plus de liberté, mais ils ont également tendance à causer beaucoup de problèmes.


0 commentaires

0
votes

L'avantage d'un pointeur est que vous ne pouvez rien passer, c'est-à-dire. Utilisez-le comme si le paramètre était complètement facultatif et ne pas avoir une variable, l'appelant passe dans.

Les références autrement sont plus sûres, si vous en avez une garantie d'exister et d'être écrite (sauf conscience)

Je pense que c'est une question de préférence autrement, mais je n'aime pas mélanger les deux, car je pense que cela facilite la maintenance et la lisibilité de votre code plus difficile à faire (surtout que vos 2 fonctions sont identiques à l'appelant)


0 commentaires

5
votes

Avantages à passer par référence:

  • oblige l'utilisateur à fournir une valeur.
  • Moins d'erreur - PRONE: Poignez le pointeur latéraison du pointeur lui-même. Ne pas avoir à vérifier pour NULL à l'intérieur.
  • rend le code d'appel d'une beauté beaucoup plus propre.

    Avantages au pointeur de passage de la valeur:

    • permet à NULL d'être transmis pour les paramètres "facultatifs". Un peu un piratage laid, mais parfois utile.
    • Les Forces de l'appelant pour savoir ce qui est fait avec le paramètre.
    • donne au lecteur une demi-indice de ce qui pourrait être fait avec le paramètre sans avoir à lire l'API.

      Etant donné que la transmission de la référence est dans la langue, tout paramètre non-pointeur peut également être modifié et vous ne sait que les valeurs du pointeur sont modifiées. J'ai vu des API où ils sont traités comme des constantes. Donc, le passage du pointeur ne donne pas vraiment à des lecteurs aucune information sur laquelle ils peuvent compter. Pour certaines personnes qui pourraient être assez bonnes, mais pour moi, ce n'est pas le cas.

      Vraiment, le pointeur qui passe est juste une restes de piratage désordonnée d'erreur de C, ce qui n'avait pas d'autre moyen de passer des valeurs par référence. C ++ a un moyen, de sorte que le hack n'est plus nécessaire.


0 commentaires

3
votes

Je vous recommande de EM> em> strong> (peut ne pas être le meilleur pour chaque situation) renvoyant foo de la fonction plutôt que de modifier un paramètre. Votre prototype de fonction ressemblerait à ceci:

Foo GetFoo() // const (if a member function)
  • Vous évitez tous les problèmes de pointeur / de référence li>
  • simplifie la vie de l'appelant. Peut transmettre la valeur de retour à d'autres fonctions sans utiliser de variable locale, par exemple Li>
  • L'appelant ne peut pas ignorer le statut d'erreur si vous lancez une exception. Li>
  • L'optimisation de la valeur de retour signifie qu'il peut être aussi efficace que la modification d'un paramètre. li> ul> p>


2 commentaires

Une exception peut parfois être une mauvaise option pour signaler une erreur. Mes deux derniers projets ont été construits avec -No-Exceptions drapeau, laissant la seule option pour signaler une erreur en renvoyant une valeur ...


@Sadsiido: Bien sûr. J'ai dit: "... Utiliser une exception pourrait être une meilleure stratégie." Vous avez dit: "Une exception peut parfois être une mauvaise option ...". Les deux déclarations sont correctes. En général, cependant, je pense que les exceptions sont une meilleure solution.



0
votes

Ces jours-ci, j'utilise des références de const pour les paramètres d'entrée et les pointeurs pour les paramètres Out. FWIIW, Guide de style Google C ++ recommande la même approche (non que je suis toujours d'accord avec leur guide de style - par exemple, ils n'utilisent pas d'exceptions, ce qui n'a généralement pas beaucoup de sens)


0 commentaires

0
votes

Ma préférence est une référence. Tout d'abord, parce que ça rime. :) En outre, à cause des problèmes indiqués par d'autres réponses: pas besoin de déréférence, et aucune possibilité d'une référence n'étant nulle. Une autre raison, que je n'ai pas vue mentionnée, est que lorsque vous voyez un pointeur, vous ne pouvez pas être sûr de savoir si elle pointe ou non de la mémoire allouée de manière dynamique, vous pouvez être tenté d'appeler Supprimer . Une référence, d'autre part, distribue avec toute ambiguïté en matière de gestion de la mémoire.

Cela dit, il y a bien sûr de nombreux cas lors du passage d'un pointeur est préférable, voire nécessaire. Si vous savez à l'avance, le paramètre est facultatif, laissez-le être null est très utile. De même, vous pouvez savoir à l'avance que le paramètre est toujours alloué de manière dynamique et que la gestion de la mémoire a tout fonctionné.


0 commentaires