web-dev-qa-db-fra.com

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 comme pointeurs dont je peux obtenir la valeur en utilisant *x. Lorsque j'appelle f j'ai besoin de passer l'adresse de mes arguments passés, c'est pourquoi je passe &a, &b. f2 est le même sauf que la définition est différente.

Maintenant ma question est: sont-ils vraiment les mêmes concernant la gestion de la mémoire? Les deux ne font aucune copie de la valeur transmise mais transmettent plutôt une référence? Je me pose des questions sur f2 car je n'ai pas pu lire l'adresse de x dans f2 donc je sais plus sur x et y dans f (là je connais l'adresse ET la valeur).

Merci d'avance!

Edit : D'accord merci, après avoir fait plus de recherches, j'ai trouvé un sujet assez utile:

Pointer vs. Reference Il existe également un lien vers les directives de codage de Google http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments qui est assez useful J'ai l'impression (comme je l'ai compris maintenant, c'est une forme de goût du sujet) de faire plus clair

54
tim

f2 prend ses arguments par référence, qui est essentiellement un alias pour les arguments que vous passez. La différence entre le pointeur et la 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, où quand vous passez par référence vous passez simplement les paramètres et l'alias est créé.

En passant par la référence const (const double& ref) est préférable lorsque vous n'allez pas changer les arguments à l'intérieur de la fonction, et quand vous allez les changer, utilisez une référence non const.

Les pointeurs sont surtout utilisés lorsque vous devez être en mesure de passer NULL à vos paramètres, vous devrez évidemment vérifier dans votre fonction si le pointeur n'était pas NULL avant de l'utiliser.

54
Tony The Lion

C'est juste 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.

13
philfr

Une autre différence qui n'a pas été mentionnée est que vous ne pouvez pas changer la référence à une référence. 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; // change value of X
rY = 25;  // change value of Y

pX = Y;   // pX now points to 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 dans des tableaux simples comme des pointeurs.

10
DanS

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 grand et passer un struct ou class pourrait être très important en effet.
Mais en passant un pointeur à quelque chose, eh bien, vous passez juste une adresse par valeur. (Un pointeur est souvent une taille pratique pour le CPU comme un int.)
Une référence est très similaire, et je pense certainement à une référence comme un pointeur, mais avec du sucre syntaxique pour la faire ressembler à 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;           // pointer to i
int* const cp = p;     // cp points to i, but cp cannot be modified
p = &j;                // OK - p is modified to point to j
*cp = 0;               // OK - i is overwritten
cp = &j;               // ERROR - cp cannot be modified

int& ri = i;           // ri refers to i
ri = 1;                // i is overwritten
ri = j;                // i is overwritten again
                       // Did you think ri might refer to j?

Ainsi, un pointeur double le temps: il s'agit d'une valeur à part entière, mais il peut également pointer vers une autre valeur lorsque vous déréférencez-la, 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 de l'exprimer.

Une référence est supposée ne pas 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 pdevrait a été vérifié avant d'être utilisé dans l'appel à foo:

if (p) foo(*p);
6
quamrana

Vous devriez avoir pu lire l'adresse x dans les deux fonctions.

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

Une différence notable entre les références et les pointeurs est que les premiers ne peuvent pas être NULL. Vous devez transmettre quelque chose (valide) tout en fournissant un pointeur, vous devez spécifier dans la documentation si le passage NULL est autorisé/bien défini.

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

2
ereOn