Question

Quelle serait la meilleure pratique pour donner à une fonction la variable d'origine avec laquelle travailler:

unsigned long x = 4;

void func1(unsigned long& val) {
     val = 5;            
}
func1(x);

ou:

void func2(unsigned long* val) {
     *val = 5;
}
func2(&x);

IOW: Y a-t-il une raison de choisir un sur un autre?

Était-ce utile?

La solution

Ma règle générale est la suivante:

Utilisez des pointeurs si vous souhaitez effectuer une arithmétique de pointeur avec eux (par exemple, incrémenter l'adresse du pointeur pour parcourir un tableau) ou si vous devez passer un pointeur NULL.

Utilisez les références autrement.

Autres conseils

Je pense vraiment que vous bénéficierez de l’établissement des instructions de codage d’appel de fonction suivantes:

  1. Comme partout ailleurs, restez toujours const -correct.

    • Remarque: cela signifie notamment que seules les valeurs supérieures (voir élément 3) et les valeurs passées par valeur (voir élément 4) peuvent ne pas avoir le spécificateur const .
  2. Ne transmettez une valeur par pointeur que si la valeur 0 / NULL est une entrée valide dans le contexte actuel.

    • Justification 1: En tant que appelant , vous constatez que tout ce que vous passez dans doit être dans un état utilisable.

    • Justification 2: comme , , vous savez que tout ce qui entre est dans un état utilisable. Par conséquent, aucune vérification NULL ou traitement d'erreur ne doit être effectué pour cette valeur.

    • Justification 3: les justifications 1 et 2 seront appliquées par le compilateur . Attrapez toujours les erreurs au moment de la compilation si vous le pouvez.

  3. Si un argument de fonction est une valeur de sortie, transmettez-le par référence.

    • Raison: Nous ne voulons pas casser le point 2 ...
  4. Choisissez "transmettre par valeur" sur " passer par référence constante " uniquement si la valeur est un POD ( plaine ancienne Datastructure ) ou suffisamment petite ( mémoire) ou d’une autre manière assez peu coûteuse (copie temporelle).

    • Justification: évitez les copies inutiles.
    • Remarque: assez petit et assez bon marché ne sont pas des éléments mesurables absolus.

Cela finit par être subjectif. Jusqu'ici, la discussion est utile, mais je ne pense pas qu'il y ait une réponse correcte ou décisive à cette question. Cela dépendra beaucoup des directives de style et de vos besoins du moment.

Bien qu'il existe différentes capacités (qu'un élément puisse ou non être NULL) avec un pointeur, la plus grande différence pratique pour un paramètre de sortie est purement syntaxique. Guide de style C ++ de Google ( https://google.github.io/styleguide/cppguide.html# Référence_Arguments ), par exemple, ne commande que les pointeurs pour les paramètres de sortie et autorise uniquement les références qui sont const. Le raisonnement en est un de lisibilité: quelque chose avec une syntaxe de valeur ne devrait pas avoir de signification sémantique de pointeur. Je ne dis pas que c'est forcément vrai ou faux, mais je pense que le problème ici est que c'est une question de style, pas de correction.

Vous devez passer un pointeur si vous souhaitez modifier la valeur de la variable. Même si techniquement, le renvoi d'une référence ou d'un pointeur est identique, le passage d'un pointeur dans votre cas d'utilisation est plus lisible, car il "annonce". le fait que la valeur sera modifiée par la fonction.

Si vous avez un paramètre où il peut être nécessaire d'indiquer l'absence de valeur, il est courant de lui attribuer la valeur d'un pointeur et de le transmettre à NULL.

Une meilleure solution dans la plupart des cas (du point de vue de la sécurité) consiste à utiliser boost :: facultatif . Cela vous permet de transmettre des valeurs optionnelles par référence et également en tant que valeur de retour.

// Sample method using optional as input parameter
void PrintOptional(const boost::optional<std::string>& optional_str)
{
    if (optional_str)
    {
       cout << *optional_str << std::endl;
    }
    else
    {
       cout << "(no string)" << std::endl;
    }
}

// Sample method using optional as return value
boost::optional<int> ReturnOptional(bool return_nothing)
{
    if (return_nothing)
    {
       return boost::optional<int>();
    }

    return boost::optional<int>(42);
}

Utilisez une référence lorsque vous le pouvez, utilisez un pointeur lorsque vous devez. De la FAQ C ++: "Quand devrais-je utiliser des références et quand devrais-je utiliser des pointeurs? "

Pointeurs

  • Un pointeur est une variable qui contient une adresse de mémoire.
  • Une déclaration de pointeur se compose d'un type de base, d'un * et du nom de la variable.
  • Un pointeur peut pointer sur un nombre quelconque de variables dans la durée de vie
  • Un pointeur qui ne pointe pas actuellement vers un emplacement mémoire valide reçoit la valeur null (qui est zéro)

    BaseType* ptrBaseType;
    BaseType objBaseType;
    ptrBaseType = &objBaseType;
    
  • Le & amp; est un opérateur unaire qui renvoie l'adresse mémoire de son opérande.

  • L'opérateur de déréférencement (*) permet d'accéder à la valeur stockée dans la variable pointée par le pointeur.

       int nVar = 7;
       int* ptrVar = &nVar;
       int nVar2 = *ptrVar;
    

Référence

  • Une référence (& amp;) est comme un alias d'une variable existante.

  • Une référence (& amp;) est comme un pointeur constant qui est automatiquement déréférencé.

  • Il est généralement utilisé pour les listes d'arguments de fonction et les valeurs de retour de fonction.

  • Une référence doit être initialisée lors de sa création.

  • Une fois qu'une référence est initialisée à un objet, elle ne peut plus être modifiée pour faire référence à un autre objet.

  • Vous ne pouvez pas avoir de références NULL.

  • Une référence const peut faire référence à un const int. Il est fait avec une variable temporaire avec la valeur de la const

    int i = 3;    //integer declaration
    int * pi = &i;    //pi points to the integer i
    int& ri = i;    //ri is refers to integer i – creation of reference and initialization
    

 entrer la description de l'image ici

 entrer la description de l'image ici

Une référence est un pointeur implicite. En principe, vous pouvez modifier la valeur indiquée par la référence, mais vous ne pouvez pas modifier la référence pour indiquer autre chose. Donc, mes 2 centimes sont que si vous voulez seulement changer la valeur d'un paramètre, transmettez-le comme référence mais si vous devez modifier le paramètre pour qu'il pointe vers un autre objet, transmettez-le à l'aide d'un pointeur.

Considérons le mot clé de C #. Le compilateur nécessite que l'appelant d'une méthode applique le mot clé out à tous les arguments out, même s'il sait déjà s'ils le sont. Ceci est destiné à améliorer la lisibilité. Bien qu'avec les IDE modernes, je suis enclin à penser qu'il s'agit d'un travail de mise en évidence de la syntaxe (ou de la sémantique).

Passer par référence constante sauf s’il existe une raison pour laquelle vous souhaitez modifier / conserver le contenu que vous transmettez.

Ce sera la méthode la plus efficace dans la plupart des cas.

Assurez-vous que vous utilisez const pour chaque paramètre que vous ne souhaitez pas modifier, car cela vous empêche non seulement de faire quelque chose de stupide dans la fonction, mais donne également une bonne indication aux autres utilisateurs de ce que la fonction fait des valeurs passées. Cela inclut la création d’un pointeur constant lorsque vous souhaitez uniquement modifier les éléments pointés vers ...

Pointeurs:

  • Peut recevoir nullptr (ou NULL ).
  • Sur le site de l'appel, vous devez utiliser & amp; si votre type n'est pas un pointeur lui-même, faisant explicitement que vous modifiez votre objet.
  • Les pointeurs peuvent être rebondis.

Références:

  • Ne peut être nul.
  • Une fois lié, vous ne pouvez pas changer.
  • Les appelants n'ont pas besoin d'utiliser explicitement & amp; . Ceci est considéré parfois mauvais parce que vous devez aller à la mise en œuvre de la fonction pour voir si votre paramètre est modifié.

Une référence est similaire à un pointeur, sauf que vous n'avez pas besoin d'utiliser un préfixe & # 8727; accéder à la valeur référencée par la référence. De même, il est impossible de faire référence à un objet différent après son initialisation.

Les références sont particulièrement utiles pour spécifier les arguments de la fonction.

Pour plus d'informations, voir "Visite guidée en C ++". par "Bjarne Stroustrup" (2014) Pages 11-12

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