Bonjour, ma question est simple :
Y-a-t'il une différence entre
etCode:
1
2
3
4 void foo(int* v); // ... int* x; foo(x);
?Code:
1
2
3
4 void foo(int &v); // ... int x; foo(*x);
Version imprimable
Bonjour, ma question est simple :
Y-a-t'il une différence entre
etCode:
1
2
3
4 void foo(int* v); // ... int* x; foo(x);
?Code:
1
2
3
4 void foo(int &v); // ... int x; foo(*x);
Aucun des exemples ne passe un pointeur par référence!
Le premier passe un pointeur par valeur.
Le second utilise une l-reférence (et il ne faut pas utiliser d'étoile à l'appel)
Un pointeur référence, c'est celaCode:
1
2
3
4
5
6
7
8
9
10 int a; void fct( int*& r ) { // passage par référence d'un pointeur r = &a; } int main() { int *x; // pointeur pas encore initialisé fct( x ); assert( x == &a ); // le pointeur pointe bien sur a }
Pardon, je voulais écrire ça pour le 2e cas.Code:
1
2
3
4 void foo(truc &v); // ... truc* x; foo(*x);
Comme ça je peux utiliser truc.machin() au lieu de truc->machin() dans la fonction foo.
Ça fonctionne correctement mais j'ai l'impression que c'est ultra stupide de faire comme ça :mrgreen:
Intéressant :)
Je vais bientôt refaire du C/C++ :)
Il n'y avait pas de différences réellement entre les pointeurs et les références ? Sûr ? Il me semble pourtant, c'est pas qu'une question de confort, il aurait pas fait ça ? Si ?
Les pointeurs et mes références sont deux principes différents.On peut donc choisir de passer un paramètre par référence ou son adresse par un pointeur. Les 2 rendent un service similaire dans ce cas. On doit normalement préférer l'utilisation de la référence à celui d'un pointeur.
- Le pointeur est une variable qui peut en désigner une autre.
Un pointeur peut ne rien désigner (pointeur nul) et peut changer de valeur pour désigner autre chose. On peut pointer sur un pointeur ou avoir un tableau de pointeurs ou les référencer.- Une référence c'est un alias vers une variable.
Elle est associée à toujours la même variable et ne correspond jamais à nul. On ne peut pas pointer sur une référence, référencer une référence ou les mettre en tableau.
On distingue les l-références qui référencent une l-value (donc une variable ou une allocation du tas) et les r-références qui référencent les temporaires et les x-values.
Une référence peut "prolonger la vie" d'un temporaire; La temporaire associée à une const l-référence ou à une r-référence ne sera détruite qu'à la fin de vie de la référence.Code:
1
2
3
4
5
6
7
8
9 Objet fct(); void fct2( Objet const& ); void fct3( Objet const* ); { Objet const& x = fct(); // La fct a retourné un 1er objet, x le référence fct2( fct() ); // La fct a retourné un 2nd objet qui est détruit dès le retour de fct2() fct3( &fct() ); // impossible!! fct3( &x ); // Ok, on transmet un pointeur sur 1er objet ... } // x est détruite, Le 1er objet est détruit
Si tu espères passer un pointeur par référence, il faut commencer par l'écrire.
Là tu as... une référence. Où vois-tu un pointeur dans ta signature ? :weird:
void foo(truc* &v);
Et à moins que ta fonction modifie le pointeur (et non que les données pointées), oui ça n'a aucun intérêt.
Au contraire. C'est très intelligent: tu affirmes depuis la fonction appellée "Tu DOIS me passer un truc valide". Il te manque toutefois une vérification depuis la fonction appelante.
Dit autrement, les codes clients valides (à supposer que tu partes d'un pointeur) sont:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13 // truc *x = ... // soit 1: assert(x && "Ouhla! ce n'est pas censé se produire ce truc!!"); // si tu sais que la nullité n'a pas de sens foo(*x); // C'est un cas à rapprocher de // gsl::non_null<truc> x = ... // Cf les C++ Core Guidelines et GSL // soit 2: // si tu sais que la validité de x est liée à une entrée externe que tu ne peux pas controler et que tu ne pourras pas connaitre avant l'exécution if (!x) throw std::runtime_error("entrée utilisateur non valide"); foo(x);
Mais on peut aussi partir de valeurs optionnelles (C++17)
Code:
1
2 std::optional<truc> x = ...; if (x) foo(*x);
Tu peux te reférer à mes 3 billets sur la programmation par contrat en C et C++. Les deux premiers ont été republiés sur dvpz -- j'ai de la relecture à faire avant de faire pareil avec le 3e.
Il y a une différence côté invariants: avec une référence que tu affirmes que ce n'est pas censé être nul donc. C'est plus qu'une simple question de confort.
Après, techniquement parlant, dans le cas des variables, avec une référence, il y a plus de chances que le compilateur dégage la variable qu'avec un pointeur.
Code:
1
2
3
4 int a = 42; int &j = a; // aucune chance d'avoir une existance propre int *p = a; // aura une existance propre en debug, en release, je ne saurai dire
Après, si ta question est "Est-il idiot de passé un pointé par référence?", la réponse est non.
Un pointeur et une référence remplissent un rôle similaire: désigner quelque chose.
Le pointeur est comme un panneau, tu peux le changer de direction, mais il faut aller à la destination pour y trouver la chose.
La référence est plus comme un hologramme du désigné, tu ne peux pas changer ce qui est reproduit, mais tu n'as pas besoin d'aller le chercher.