113 votes

Différence entre les arguments de fonction déclarés avec & et * en C++

J'ai tapé l'exemple suivant :

#include <iostream>
double f(double* x, double* y)
{
    std::cout << "val x: " << *x << "\n";
    std::cout << "val y: " << *y << "\n";
    return *x * *y;
}
double f2(double &x, double &y)
{
    std::cout << "val x: " << x << "\n";
    std::cout << "val y: " << y << "\n";
    return x * y;
}
int main()
{
    double a, b;
    a = 2;
    b = 3; 
    std::cout << f(&a, &b) << "\n";
    std::cout << f2(a, b) << "\n";
    return 0;
}   

Dans la fonction f, je déclare x et y en tant que pointeurs dont je peux obtenir la valeur en utilisant *x. Lors de l'appel de f, je dois passer l'adresse de mes arguments passés, c'est pourquoi je passe &a, &b. f2 est la même sauf que la définition est différente.

Maintenant ma question est : Sont-ils vraiment les mêmes en ce qui concerne la gestion de la mémoire ? Les deux ne font pas de copie de la valeur passée mais passent plutôt une référence ? Je me demande à propos de f2 car je n'ai pas pu lire l'adresse de x dans f2sais plus sur x et y dans `f` (là je connais l'adresse ET la valeur).

``

Éditer : Après avoir fait des recherches supplémentaires, j'ai trouvé un sujet assez utile :

Pointeur vs Référence Il y a aussi un lien vers les directives de codage de google http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments qui est assez utile je trouve (comme je l'ai compris maintenant, c'est une forme de goût subjectif) pour être plus clair.

``

99voto

Tony The Lion Points 28208

f2 prend ses arguments par référence, ce qui est essentiellement un alias pour les arguments que vous passez. La différence entre pointeur et référence est qu'une référence ne peut pas être NULL. Avec le f, vous devez passer l'adresse (en utilisant l'opérateur &) des paramètres que vous passez au pointeur, tandis que lorsque vous passez par référence, vous passez simplement les paramètres et l'alias est créé.

Il est préférable de passer par référence constante (const double& ref) lorsque vous ne prévoyez pas de modifier les arguments à l'intérieur de la fonction, et lorsque vous allez les modifier, utilisez la référence non-constante.

Les pointeurs sont principalement utilisés lorsque vous avez besoin de pouvoir passer NULL à vos paramètres, évidemment vous devriez alors vérifier à l'intérieur de votre fonction si le pointeur n'était pas NULL avant de l'utiliser.

32voto

philfr Points 540

Ceci n'est que du sucre syntaxique pour éviter d'avoir à utiliser * à chaque fois que vous référencez l'argument. Vous pouvez toujours utiliser & pour avoir l'adresse de x dans f2.

17voto

quamrana Points 6411

Dans ma tête, les paramètres des fonctions sont toujours passés par valeur. Passer un int est facile à imaginer, passer un double est juste plus gros et passer une struct ou une class pourrait être très gros en effet.
Mais passer un pointeur vers quelque chose, et bien, vous passez simplement une adresse par valeur. (Un pointeur est souvent une taille pratique pour le processeur tout comme un int.)
Une référence est très similaire, et certainement je pense à une référence comme un pointeur, mais avec du sucre syntaxique pour donner l'impression que l'objet auquel elle se réfère a été passé par valeur.

Vous pouvez également considérer une référence comme un pointeur const, c'est-à-dire :

int i;
int j;
int* p = &i;           // pointeur vers i
int* const cp = p;     // cp pointe vers i, mais cp ne peut pas être modifié
p = &j;                // OK - p est modifié pour pointer vers j
*cp = 0;               // OK - i est écrasé
cp = &j;               // ERREUR - cp ne peut pas être modifié

int& ri = i;           // ri se réfère à i
ri = 1;                // i est écrasé
ri = j;                // i est écrasé à nouveau
                       // Pensiez-vous que ri pourrait se référer à j ?

Donc, un pointeur fait double emploi: C'est une valeur en soi, mais il peut également pointer vers une autre valeur lorsque vous le déréférencez, par exemple : *p.
De plus, avoir des paramètres de référence signifie que vous ne pouvez pas les faire se référer à autre chose pendant la durée de vie de la fonction car il n'y a aucun moyen d'exprimer cela.

Une référence n'est pas censée pouvoir être initialisée avec null, mais considérez ceci :

void foo(int& i);

int* p = 0;
foo(*p);

Cela signifie que les pointeurs doivent être vérifiés avant de les utiliser, mais les références ne peuvent pas être vérifiées. L'implémentation de foo() pourrait essayer de lire ou d'écrire dans i ce qui entraînera une violation d'accès.

Dans l'exemple ci-dessus, le pointeur p aurait dû être vérifié avant d'être utilisé dans l'appel à foo :

if (p) foo(*p);

14voto

DanS Points 755

Une autre différence qui n'a pas été mentionnée est que vous ne pouvez pas modifier ce à quoi une référence se réfère. Cela ne fait pas beaucoup de différence dans l'exemple d'appel de fonction montré dans la question d'origine.

int X(10), Y(20);
int *pX = X;
int& rY = Y;

*pX = 15; // changer la valeur de X
rY = 25;  // changer la valeur de Y

pX = Y;   // pX pointe désormais vers Y

rY pointe toujours vers Y et ne peut pas être déplacé.

Les références ne peuvent pas être utilisées pour indexer des tableaux simples comme les pointeurs.

2voto

ereOn Points 18624

Vous auriez dû pouvoir lire l'adresse x dans les deux fonctions.

Pour le faire dans f2, vous devez bien sûr préfixer x par un & car là, x est une référence à un double, et vous voulez une adresse.

Une différence notable entre les références et les pointeurs est que les premières ne peuvent pas être NULL. Vous devez passer quelque chose (de valide) tandis que lors de la fourniture d'un pointeur, vous devez spécifier dans la documentation si le passage de NULL est autorisé/bien défini.

Une autre différence est une question de lisibilité : utiliser des références au lieu de pointeurs (quand c'est possible) rend le code moins encombré avec des * et des ->.

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