Pointeurs et références en C + + Partie 2

2 mai 2009 · Posté dans C / C + +

Poursuivant cette tentative à la série des articles sur les pointeurs et les références, qui se mit à parler des pointeurs , les références de discuter aujourd'hui.

Une référence est un alias pour un objet, un alias. D'ailleurs, qui dit que ce n'est pas moi, mais la très Bjarne Stroustrup , autour du thème 5.5 de son livre , dont le contenu est si bon que je ne remarque maintenant que la couverture a une vague déferlante en forme de C. J'aime bien cette couverture!

Déclarant Références

Une référence à un type particulier est déclaré en ajoutant le caractère & (esperluette ou et commercial ) après le nom du type de référence. Notez que la même manière que dans la déclaration de pointeurs, nous traitons le caractère & à titre de matelot, et non un opérateur. Il ya une déclaration de l'opérateur de pointeurs ou des références. C'est juste une notation de la langue. Étant donné un type T, l'expression signifie T & T de référence. Par exemple:

  / / Déclare une variable entière original.
 / / Il pourrait également être char, float, etc.
 int i;

 / / Declare références à la variable i.
 / / Toutes les formes sont équivalentes, mais je préfère le premier.
 / / Notez que les types de références doivent être les mêmes
 / / Les variables référencées.
 ra = i ; int & ra = i;
 rb = i ; RB int i = &;
 rc = i ; int & rc = i;

 / / Contrairement aux pointeurs, la ligne de produit en dessous d'un
 / Erreur de compilation /.  Vous pourriez dire pourquoi?
 r1, & r2 ; int & R1, R2 et; 

Alors que dans les références C + + rappeler quelques conseils, ils sont très différents. Contrairement à ce qui se passe avec des pointeurs, une référence doit être initialisée dans sa déclaration. Essayer de déclarer une référence sans l'initialiser génère une erreur lors de la compilation, à savoir le compilateur cracher au visage "Lost Playboy a perdu." La seule exception à cette règle de renvoi a déclaré que extern , car ils seront initialisées à tout autre point du programme, mais c'est une autre conversation.

Si vous essayez de tricher en déclarant une référence externe sans l'initialiser le compilateur ne se plaindra pas. Si elle n'est jamais utilisée, cliquez sur OK. Si le compilateur est intelligent et notez qu'il ne sera pas utilisé, il peut même le retirer de la liste des symboles. Mais si elle est utilisée n'importe où dans le programme, l'éditeur de liens va se moquer de votre visage, en riant, "undefined reference to 'nome_da_variavel». Donc, bien faire les choses. Déclarée une référence? Ainsi, il iniclalize. extern? Etes-vous sûr que vous savez ce que vous faites?

La logique derrière cela est que la référence a été conçu comme un nom pour quelque chose. Si vous ne démarre pas, il ne sera pas le nom pour rien, alors il est logique. Un détail important est que très partir d'une référence n'est pas d'attribuer une valeur à elle. Comme le dit Bjarne prório, aucun opérateur opère sur des références, soit il n'est pas possible de céder, additionner, soustraire, etc avec une référence. À titre de référence est un alias pour un objet, chaque opérateur agit objet NESE, pas dans la référence. Une fois initialisé, une référence toujours référence au même objet.

Le premier piège avec des références, ainsi que des pointeurs est la question de la taille. Bien que la taille d'un pointeur (structures de données et d'autres) peuvent être obtenus avec l'opérateur sizeof, la taille d'une référence ne peut être obtenue par des techniques classiques, puisque lors de l'application de l'opérateur sizeof sur une référence, nous sommes effectivement l'application de l'opérateur sur l'objet auquel elle fait référence, comme nous l'avons vu dans le paragraphe précédent.

  17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
  char c;
 int i;
 Double D;

   rc = c ; char & rc = c;
    ri = i ; int & ri = i;
 rd = d ; Double & e = d;

 / / L'opérateur sizeof dit la taille du type de son argument.
 "Size of char:    " << sizeof ( c ) << " bytes" << endl ; cout <<"Taille du char:" <<sizeof (c) <<"octets" <<endl;
 "Size of int:     " << sizeof ( i ) << " bytes" << endl ; cout <<"taille de int:" <<sizeof (i) <<"octets" <<endl;
 "Size of double:  " << sizeof ( d ) << " bytes" << endl ; cout <<"Taille du double:" <<sizeof (d) <<"octets" <<endl;

 endl ; cout <<endl;

 "Size of char&:   " << sizeof ( rc ) << " bytes" << endl ; cout <<"Taille du char &:" <<sizeof (rc) <<"octets" <<endl;
 "Size of int&:    " << sizeof ( ri ) << " bytes" << endl ; cout <<"taille de int &:" <<sizeof (ri) <<"octets" <<endl;
 "Size of double&: " << sizeof ( rd ) << " bytes" << endl ; cout <<"taille de la double &:" <<sizeof (e) <<"octets" <<endl; 

Les techniques d'obtention de la taille des références sont au-delà du champ d'application de ce texte, mais j'ai l'intention d'en parler plus tard. Pour l'instant, je dirai juste que sans démontrer que, le cas échéant, de la taille d'une référence est identique à la taille d'un pointeur.

La bonne partie de l'histoire est que, souvent, la taille des pointeurs et les références sont beaucoup moins pertinent que la taille de l'objet pointu ou visées. J'ai particulièrement jamais eu besoin d'utiliser cette information, mais pour le développement ou sur différentes architectures pour les systèmes embarqués, il est devenu plus intéressant.

Utilisation des références

L'utilisation de références est maintenant beaucoup plus simple que les pointeurs, parce que les opérateurs ne sont pas nécessaires pour extraire les adresses ou l'utilisation de références. Référence des variables sont utilisées comme des variables communes, notant que l'opération effectuée sur une référence toujours une incidence sur l'objet référencé.

  17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
  int x, y;
 rx = x ; int & rx = x;
 ry = y ; int & ry = y;

 ; x = 13;
 ; y = 10;

 ; // A atribuição é automaticamente aplicada em x. rx = 42 / / La cession est automatiquement appliqué à x.
 // O incremento é automaticamente aplicado em y. ry + + / / L'augmentation est automatiquement appliqué à y.

 "x:  " << x << endl ; // Valor de x. cout <<"x:" <<x <<endl / / valeur de x.
 "y:  " << y << endl ; // Valor de y. Cout <<"Y:" <<y <<endl / / valeur de y.
 "rx: " << rx << endl ; // Valor de rx == x. cout <<"rx:" <<rx <<endl / / Valeur Rx == x.
 "ry: " << ry << endl ; // Valor de ry == y. Cout <<"Ry:" <ry <<<endl / / ry value == y. 

En utilisant comme référence est transparente pour le programmeur, il n'a pas besoin de savoir qui est une référence. Il suffit d'utiliser comme une variable ordinaire. Avec mon imagination limitée ne vois pas comment quelqu'un peut être excommunié pour l'utilisation de termes de façon inappropriée. Bien que toujours un certain esprit de porc qui peut faire chier avec des références, est beaucoup plus facile d'obtenir déclenché par Saci à manipuler des pointeurs.

Adresses et références

Du point de vue de Murphy , les références sont laids, ennuyeux et ridicules, parce que il ya peu de risque potentiel pour faire avec eux. Même si il ya beaucoup de surprises adresse (sera?). Considérons le code ci-dessous:

  17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
  10 ; int a = 10;
 13 ; int b = 13;

 ra = a ; int & ra = a;
 rb = b ; int & rb = b;

 ; RA = 42;
 ; RB = 7;

 "ra  = " << ra << endl ; // O valor de ra == 42. cout <<"ra =" <<Ra <<endl / / La valeur de ra == 42.
 "rb  = " << rb << endl ; // O valor de rb == 7. cout <<"rb =" <rb <<<endl / / La valeur de RB == 7.
 "a   = " << a << endl ; // O valor de a == ra == 42. Cout <<"a =" <<a <<endl / / La valeur de la RA == == 42.
 "b   = " << b << endl ; // O valor de b == rb == 7. cout <<"b =" <<b <<endl / / La valeur de rb b == == 7.

 "&a  = " << & a << endl ; // O endereço de a. cout <<"& a =" <<a <<endl / / L'adresse de a.
 "&b  = " << & b << endl ; // O endereço de b. cout <<"& b =" <<b <<endl / / L'adresse de b.
 "&ra = " << & ra << endl ; // O endereço de ra == &a. cout <<"& ra =" <<Ra <<endl / / L'adresse de ra == & a.
 "&rb = " << & rb << endl ; // O endereço de rb == &b. cout <<"& rb =" <<<rb <endl / / L'adresse de rb == & b. 

Sur les lignes 17:18 Je déclare deux variables entières (aurait pu faire cela avec un exemple ...). Sur les lignes 20:21 Je déclare deux références, le référencement des deux variables précédentes. Par la suite, la RA et RB variables ne sont que des alias pour les variables a et b. Comme nous l'avons vu précédemment, un opérateur appliqué au fonctionnement réel de références sur les objets référencés, de sorte que chaque paire de variables de référence a toujours la même valeur.

La partie intéressante à noter est que les adresses des références sont exactement les mêmes adresses des variables font référence, à la différence des pointeurs qui ont leurs propres adresses. Pourquoi? Parce que vous êtes tombé dans Pegadinha ne Malandro . N'oubliez pas que parler de n'importe quel opérateur est appliqué à une référence? Eh bien, l'opérateur & est utilisé ici l'adresse "qui est aussi appliqué directement sur les variables d'origine et non pas dans les références. Les mêmes techniques utilisées ninja pour obtenir la taille des références sont nécessaires pour obtenir l'adresse d'entre eux.

Là encore, la partie la plus amusante est que le mécanisme de référence a été conçu pour être aussi transparents que possible pour le programmeur. Tailles et l'adresse physique de références sont les informations non pertinentes du point de vue de la «normale» du programme en C + +.

Différences et similitudes entre les pointeurs et les références

Les pointeurs et les références sont les mécanismes d'indirection en C + +, ou des mécanismes sont utilisés pour que, d'un symbole (variable) Je vais être capable de manipuler un autre objet.

Les principales utilisations des pointeurs sont généralement liés à la gestion et la manipulation de la mémoire dynamique, la création et la destruction des objets de formes différentes et des moments spéciaux, ainsi que "le passage de paramètres par référence» (il cite). Les références sont déjà utilisés dans le passage par référence (pourquoi?) Et la surcharge des opérateurs.

Fondamentalement, tout ce que nous pouvons faire avec des références peut être émulé avec des pointeurs. Déjà mutuellement pas toujours vrai. Le grand avantage d'entre eux, cependant, est que l'indirection devenir complètement transparent pour le programmeur.

Une intéressante allégorie pour mieux comprendre les différences entre les pointeurs et les références est le surnom. Par exemple: Imaginez qu'une personne, par exemple, Dunga , est notre variable d'origine, l'objet. Dunga est déjà une référence à Dunga, car il est un alias pour le même objet sont la même personne. Déjà mère de Dunga (ou Dunga, peu importe), qui est aussi longue citée par la foule, peut être considéré comme un pointeur vers elle, parce que certaines données des opérateurs de vocabulaire, lui fit un compliment, est en fait indirectement ciblées lui.

Liens

Commentaires

  • Bonjour,

    J'apprécie le compliment.

    Le temps est court, mais écrire les suites les plus brefs délais.
  • en attendant le juridique
  • Blab partenaire!

    Félicitations pour l'article, très bon!

    [S]
  • Ma naïveté, on pense que la question avait déjà fermé quand vous avez dit "Du point de vue de Murphy, les références sont laids, ennuyeux et ridicules, parce que il ya peu de risque potentiel pour faire avec eux." Quoi qu'il en soit, déjà recommandé votre article pour un débutant car il est effectivement très bien expliqué pour ceux qui s'aventurent pour les différences entre C et C + +.

    Je cherche des séquelles.

    [S]
  • Grand article!

    Malheureusement, les références ne sont pas aussi inoffensifs qu'ils semblent être. Imaginez les situations suivantes:


    1. Quelqu'un retourne une référence à une variable non-statique locale:


    QueroEconomizarCopiasDeString & string ()
    (
    ret chaîne;
    / / Hack hack hack
    ret retour; / / malin ...
    )


    Dans ce cas, le champ d'application se termine avant même que quelqu'un se sert de la référence.

    La solution consiste à obtenir une référence en tant que paramètre et faire une seule copie: pour la variable 'out'.


    2. Quelqu'un veut se servir de la mémoire dynamique comme des variables ordinaires:


    int main ()
    (
    int * pi = new int;

    / / Lignes de code pour oublier qui est pi

    int & ri * pi = / / Je pense que les pointeurs compliquée

    / / Plus de lignes de code à oublier ri et PI

    pi supprimer;

    / / Tcharammm ...

    Ri = 42 / / est la réponse à tout, non?
    )



    Ces exemples semblent bête, mais pas aussi improbable qu'il n'y paraît. Tout simplement le code à être passé sous silence des Design Patterns ou autres balivernes et il explose sans vous connaître ce qui s'est passé.

    [S]
  • Caloni, tu es un gars trop précipité:)

    Oui, vous avez parfaitement raison. Mais je laisse aller sur le but.
    Je n'ai pas parlé encore const pointeurs ou des références, ni même que l'association entre les pointeurs et les tableaux, mais je vais parler.

    Merci pour le compliment, c'est très motivant.

    Cheers
commentaires de blog actionnés par Disqus