Différence entre passage par référence et passage par adresse

Le problème exposé dans ce sujet a été résolu.

Bonjour,

je sais que le titre est impropre, car le passage par adresse n'est qu'un passage par valeur avec un pointeur.

Mais je voulais savoir la différence et l'intérêt d'utiliser l'un plutôt que l'autre.

Ces deux fonctions sont-elles donc totalement équivalentes et produisent-elles les mêmes instructions ?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
//1
void transformeEn6(int &a)
{
    a = 6;
}

//que j'appelle comme ça
int var;
transformeEn6(var); //var = 6

//2
void tranformeEn6(int *a)
{
    *a = 6;
}

//que j'appelle comme ça
int var;
transformeEn6(&var);

Allen Holub, donne deux règles (120 et 121) importantes concernant ta question,

Tres bof comme regles, cela semble plus a du C++ old school.

Les recommandations actuelles sont plutot vers eviter l'utilisation des pointeurs nus. Cf https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rf-conventional

Mais donc, à part ça, les mécanismes bas-niveau sont exactement les mêmes ? Ces deux fonctions sont-elles donc totalement équivalentes et produisent-elles les mêmes instructions ?

En interne, le compilateur utilisera la meme chose (une adresse dans la pile). Donc pas de difference de performance.

Mais…

Mais je voulais savoir la différence et l'intérêt d'utiliser l'un plutôt que l'autre.

Tu ne sais pas comment tes fonctions seront utilisees. (oui, tu sais comment tes fonctions sont appellees quand tu travailles tout seul sur un hello world, mais pas quand tu bosses dans une equipe sur un programme de 100 000 lignes de code).

Un pointeur PEUT etre invalide, donc il doit TOUJOURS etre verifier avant utilisation, avec un assert ou un if. Ton code avec pointeur n'est donc pas correct.

La version avec reference doit donc etre privilegiee. (En fait, tu peux meme oublier pendant quelques temps les pointeurs nus si tu debutes).

EDIT:

la valeur n'est pas null (plus en C++17?)

Pas vu de changement de ce cote en C++17 ou dans les drafts.

+1 -0

Concentre-toi sur C++20 :p

Plus sérieusement, intéresse-toi au moins à C++11 qui simplifie énormément de chose et permet d'écrire un code plus juste. La sémantique de déplacement est l'une des nouveauté qui amènent le plus de changement.

La norme de 2014 est une évolution plutôt mineure et naturelle avec peu de changements:

  • pas de nouveau mot clef, seulement plus de possibilité et moins de contraintes.
  • peu d'ajout dans la bibliothèque standard.
  • pas ou peu de nouvelle syntaxe.

(la version 6 de gcc est en 14 par défaut)

Après ça, apprendre le 17 sera très rapide.

auto n'est pas sorti en C++14 ?

Non, C++11. (Et en fait, "auto" est déjà un mot clé en C++98/03, donc techniquement, ce n'est même pas un nouveau mot clé du C++11 :) )

Ouf, alors si je dois apprendre les nouveaux standards, en plus…

  1. pas besoin de "en plus", apprends un standard récent.
  2. A part la question de Necros211, il n'y a rien de spécifique au C++11/14/17 dans cette discussion, c'est valide pour les anciennes normes aussi.
+0 -0

Pourmoi la différence essentielle c'est que la référence ne peut jamais être nulle, elle pointe toujours vers un objet valide. A mon avis c'est la seule chose importante à retenir ici.

Oui on peut bidouiller pour la rendre nulle, mais il faut vraiment faire exprès, et à moins de savoir ce qu'on fait, on ne fait jamais ça.

L'autre message important qu'on transmet à l'utilisateur de la fonction quand on doit lui passer une référence plutôt qu'un pointeur, c'est « je ne m'occupe pas de la mémoire; tu dois me donner un objet valide, et il sera encore valide après mon retour ».

+0 -0

Il a des gens qui vérifie si this = nul pour faire de la récursivité avec des structures imbriquées:

1
2
3
4
5
6
7
8
struct S {
  S * next;
  void foo() {
    if (this == nullptr) return ;
    ...
    p->next();
  }
};

Alors que déplacer la condition sur p fait tout aussi bien l'affaire.

Cela vient du fait que gcc évalue this comme un pointeur potentiellement nul. À partir de la version 6, il y a un avertissement pour les tests du genre this == nullptr. La 6.1 considère this comme toujours différent de nullptr et propose une option pour revenir au comportement précédent.

Clang considère this comme non-nul et se justifie comme suit:

warning: 'this' pointer cannot be null in well-defined C++ code; comparison may be assumed to always evaluate to true [-Wtautological-undefined-compare]

Pas plus mal que cette garantie arrive en 17.

Intuitivement, j'aurai dit que de base c'est invalide sémantiquement (mais ce serait pas le premier truc stupide dans la norme C++). Appeler une fonction membre, quelle qu'elle soit sur un this qui vaut nullptr, c'est équivalent à écrire :

1
static_cast<Foo*>(nullptr)->bar();

Foncièrement, c'est un déréférencement de la valeur nullptr. Même si on n'y fait pas d'accès. Surtout que ça ne peut fonctionner que si la fonction est non-virtuelle et qu'elle n'accède à rien de l'objet pointé avant de terminer.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte