web-dev-qa-db-fra.com

Pointeur vs référence

Quelle serait la meilleure pratique pour donner à une fonction la variable originale 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?

247
Jack Reza

Ma règle de base est:

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

Utilisez des références autrement.

275
Nils Pipenbrinck

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

  1. Comme dans tous les autres endroits, soyez toujours const- correct.

    • Remarque: Cela signifie notamment que seules les valeurs dépassées (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 voyez que tout ce que vous passez doit être dans un état utilisable.

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

    • Justification 3: les justifications 1 et 2 seront le compilateur sera appliqué. 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 "passer par valeur" sur "passer par référence const" uniquement si la valeur est un POD ( Plain old Datastructure ) ou suffisamment petite (en mémoire) ou d'une autre manière assez peu chère en temps ) copier.

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

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 fonctionnalités (que quelque chose puisse ou non être NULL) avec un pointeur, la plus grande différence pratique pour un paramètre de sortie est purement syntaxique. Le Guide de style C++ de Google ( https://google.github.io/styleguide/cppguide.html#Reference_Arguments ), par exemple, ne commande que les pointeurs pour les paramètres de sortie et n'autorise que 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.

24
Aaron N. Tubbs

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.

7
Max Caceres

Si vous avez un paramètre pour lequel vous pouvez avoir besoin d'indiquer l'absence d'une valeur, il est courant de lui attribuer une valeur de 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 :: optional . 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);
}
5
Kiley Hykawy

Pointeurs

  • Un pointeur est une variable qui contient une adresse 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 vie
  • Un pointeur qui ne pointe pas actuellement vers un emplacement mémoire valide se voit attribuer la valeur null (qui est zéro)

    BaseType* ptrBaseType;
    BaseType objBaseType;
    ptrBaseType = &objBaseType;
    
  • Le & 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 (&) ressemble à un alias d'une variable existante.

  • Une référence (&) 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. C'est fait avec une variable temporaire avec la valeur du 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
    

enter image description here

enter image description here

4
Saurabh Raoot

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

4
RezaPlusPlus

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 surbrillance syntaxique (ou sémantique).

3
Daniel Earwicker

Pointeurs:

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

Références:

  • Ne peut pas être nulle.
  • Une fois lié, ne peut pas changer.
  • Les appelants n'ont pas besoin d'utiliser explicitement &. Ceci est considéré parfois comme mauvais parce que vous devez aller à la mise en oeuvre de la fonction pour voir si votre paramètre est modifié.
2
Germán Diago

Passer en référence de const sauf s'il y a 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 ...

2
NotJarvis

Une référence est similaire à un pointeur, sauf que vous n’avez pas besoin d’utiliser un préfixe pour accéder à la valeur à laquelle la référence fait référence. De plus, il n'est pas possible 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 "Une visite du C++" de "Bjarne Stroustrup" (2014) Pages 11-12

0
amirfg