3161 votes

Quelles sont les différences entre le pointeur de variable et la variable de référence en C++?

Je sais que les références sont syntaxique de sucre, code plus facile à lire et à écrire :)

Mais quelles sont les différences?

Résumé des réponses et des liens ci-dessous:

  1. Un pointeur peut être assignée à n'importe quel nombre de fois tandis qu'une référence ne peut pas être déplacé après la liaison.
  2. Pointeurs de point de nulle part (NULL), tandis que la référence se réfèrent toujours à un objet.
  3. Vous ne pouvez pas prendre l'adresse d'une référence comme vous le pouvez avec des pointeurs.
  4. Il n'y a pas de référence de "l'arithmétique" (mais vous pouvez prendre l'adresse d'un objet pointé par une référence et ne pointeur de l'arithmétique, comme dans &obj + 5).

Pour clarifier un malentendu:

La norme C++ est très prudent pour éviter de dicter la façon dont un compilateur doit mettre en œuvre les références, mais chaque compilateur C++ implémente références (pointeurs. C'est, une déclaration telle que:

int &ri = i;

si c'est pas optimisé disparaître entièrement, alloue la même quantité de stockage comme un pointeur, et place l'adresse de je dans que de stockage.

Donc, pointeur et référence occupe la même quantité de mémoire

En règle générale,

  • Utiliser des références en fonction des paramètres et types de retour de définir utile et l'auto-documenter les interfaces.
  • Utiliser des pointeurs pour mettre en œuvre des algorithmes et structures de données.

Lecture intéressante:

1634voto

Brian R. Bondy Points 141769
  1. Un pointeur peut être ré-attribuée:

    int x = 5;
    int y = 6;
    int *p;
    p =  &x;
    p = &y;
    *p = 10;
    assert(x == 5);
    assert(y == 10);
    

    Une référence ne peut, et doit être attribuée à l'initialisation:

    int x = 5;
    int y = 6;
    int &r = x;
    
  2. Un pointeur a sa propre adresse de la mémoire et de la taille de la pile (4 octets sur x86), alors que les actions de référence de la même adresse mémoire (avec la variable d'origine), mais aussi prend de la place sur la pile. Depuis une référence a la même adresse que la variable elle-même, il est sûr de penser à une référence comme un autre nom pour la même variable. Note: Ce qu'est un pointeur peut être sur la pile ou le tas. Idem une référence. Ma demande dans cette déclaration n'est pas qu'un pointeur doit pointer vers la pile. Un pointeur est une variable qui contient une adresse mémoire. Cette variable est sur la pile. Depuis une référence a son propre espace sur la pile, et depuis l'adresse est la même que la variable de référence. De plus sur la pile vs tas. Cela implique qu'il y est une vraie adresse de référence que le compilateur ne vais pas vous dire.

    int x = 0;
    int &r = x;
    int *p = &x;
    int *p2 = &r;
    assert(p == p2);
    
  3. Vous pouvez avoir des pointeurs de pointeurs de pointeurs offrant plus de niveaux d'indirection. Alors que les références seulement offrir un niveau d'indirection.

    int x = 0;
    int y = 0;
    int *p = &x;
    int *q = &y;
    int **pp = &p;
    pp = &q;//*pp = q
    **pp = 4;
    assert(y == 4);
    assert(x == 0);
    
  4. Pointeur peut être attribué NULL directement, tandis que la référence ne peut pas. Si vous essayez assez dur, et vous savez comment, vous pouvez prendre l'adresse d'une référence NULL. De même, si vous essayez assez dur, vous pouvez disposer d'une référence à un pointeur, et alors que la référence peut contenir la valeur NULL.

    int *p = NULL;
    int &r = NULL; <--- compiling error
    
  5. Les pointeurs peuvent effectuer une itération sur un tableau, vous pouvez utiliser ++ pour passer à l'élément suivant qu'un pointeur pointant vers, et + 4 aller à la 5ème élément. Ce n'est pas une question de ce que la taille de l'objet, c'est que le pointeur pointe.

  6. Un pointeur doit être déréférencés avec * pour accéder à l'emplacement de mémoire c'points, alors qu'une référence peut être utilisé directement. Un pointeur vers un class/struct utilise -> d'accéder à ses membres alors que, d'une référence utilise un ..

  7. Un pointeur est une variable qui contient une adresse mémoire. Indépendamment de la façon dont une référence est mis en œuvre, une référence a la même adresse mémoire comme élément de référence.

  8. Les références ne peuvent pas être placés dans un tableau, alors que les pointeurs peuvent être Mentionnées par l'utilisateur @litb)

  9. Const références peuvent être liées à des temporaires. Les pointeurs ne peut pas (non sans une certaine indirection):

    const int &x = int(12); //legal C++
    int *y = &int(12); //illegal to dereference a temporary.
    

    Cela rend const& plus sûr pour une utilisation dans les listes d'arguments et ainsi de suite.

365voto

Christoph Points 64389

Ce qui est une référence C++ (langage C)

Une référence peut être considéré comme un pointeur constant (à ne pas confondre avec un pointeur vers une valeur constante!) automatique de l'indirection, c'est à dire le compilateur va appliquer l' * opérateur pour vous.

Toutes les références doivent être initialisée avec une valeur non null ou la compilation échouera. Il n'est pas possible d'obtenir l'adresse de référence - l'adresse de l'opérateur sera de retour l'adresse de la valeur de référence au lieu - ni est-il possible de faire de l'arithmétique sur des références.

C programmeurs pourraient aversion C++ références comme il n'est plus évident lorsque l'indirection se produit ou si un argument est transmis par valeur ou par pointeur sans regarder les signatures de la fonction.

Les programmeurs C++ peut aversion à l'aide de pointeurs, car ils sont considérés comme dangereux - bien que les références ne sont pas vraiment plus sûr que d'être constamment à l'exception des pointeurs dans la plupart des cas triviaux - manque la commodité de l'automatique indirection et un autre connotation sémantique.

Considérer la déclaration suivante à partir du C++ FAQ Lite:

Même si une référence est souvent mise en œuvre à l'aide d'une adresse dans le sous-jacente de l'assemblée de la langue, s'il vous plaît ne pas penser à une référence en tant que drôle à la recherche de pointeur vers un objet. Une référence est l'objet. Il est pas un pointeur vers l'objet, ni une copie de l'objet. Il estl' objet.

Mais si une référence vraiment été l'objet, comment pourrait-il en balançant les références? Dans non géré langues, il est impossible pour les références à être plus sûres que les pointeurs - là en général n'est tout simplement pas un moyen fiable alias les valeurs dans les limites du champ d'application!

Pourquoi je considère que C++ références utiles

Venant d'un C en arrière-plan, C++ références peuvent ressembler un peu idiot concept, mais on doit toujours utiliser à la place des pointeurs si possible: Automatique indirection est pratique, et les références deviennent particulièrement utiles lorsqu'il s'agit RAII - mais pas parce que de toute perception d'avantages en matière de sécurité, mais plutôt parce qu'ils font de l'écriture idiomatique code moins maladroit.

RAII est l'un des concepts centraux de C++, mais il interagit non-trivialement avec la copie de la sémantique. Les objets de passage par référence permet d'éviter ces problèmes comme aucune copie est impliqué. Si les références ne sont pas présents dans la langue, vous auriez à utiliser des pointeurs au lieu de cela, qui sont plus difficiles à utiliser, violant ainsi la langue de conception de principe que la meilleure pratique de la solution doit être plus simple que les solutions de rechange.

181voto

Matt Price Points 9674

Si vous voulez être vraiment pointilleux, il y a une chose que vous pouvez faire avec une référence que vous ne pouvez pas faire avec un pointeur: prolonger la durée de vie d'un objet temporaire. En C++, si vous liez un const référence à un objet temporaire, la durée de vie de l'objet est la durée de vie de la référence.

std::string s1 = "123";
std::string s2 = "456";

std::string s3_copy = s1 + s2;
const std::string& s3_reference = s1 + s2;

Dans cet exemple s3_copy des copies de l'objet temporaire qui est un résultat de la concaténation. Alors que s3_reference en essence devient l'objet temporaire. C'est vraiment une référence à un objet temporaire qui a maintenant la même durée de vie que de la référence.

Si vous essayez ceci sans l' const il n'arrive pas à compiler. Vous ne pouvez pas lier un non-const référence à un objet temporaire, et vous ne pouvez pas prendre son adresse.

121voto

Mark Ransom Points 132545

Contrairement à l'opinion populaire, il est possible d'avoir une référence NULL.

int * p = NULL;
int & r = *p;
r = 1;  // crash! (if you're lucky)

Accordé, il est beaucoup plus difficile à faire avec une référence - mais si vous réussissez, vous allez arracher les cheveux en essayant de les trouver.

Edit: quelques précisions.

Techniquement, c'est une référence non valide, pas une référence nulle. C++ ne prend pas en charge les références null en tant que concept, que vous pourriez trouver dans d'autres langues. Il existe d'autres types de références non valides.

L'erreur est dans le déréférencement de pointeur NULL, préalablement à l'affectation à une référence. Mais je ne suis pas au courant de tout les compilateurs qui va générer des erreurs sur cette condition - l'erreur se propage à un point plus loin dans le code. C'est ce qui rend ce problème de manière insidieuse. La plupart du temps, si vous déréférencer un pointeur NULL, vous crash à droite à cet endroit et il ne prend pas beaucoup de débogage pour le comprendre.

Mon exemple ci-dessus est court et artificiel. Voici un exemple plus réaliste.

class MyClass
{
    ...
    virtual void DoSomething(int,int,int,int,int);
};

void Foo(const MyClass & bar)
{
    ...
    bar.DoSomething(a,Long,list,of,parameters);  // crash occurs here - obvious why?
}

MyClass * GetInstance()
{
    if (somecondition)
        return NULL;
    ...
}

MyClass * p = GetInstance();
Foo(*p);

Edit: Quelques réflexions.

Je tiens à réitérer que la seule façon d'obtenir une référence null est par le biais de la malformation de code, et une fois que vous obtenez un comportement indéfini. Il ne jamais fait sens pour vérifier une référence null; par exemple, vous pouvez essayer d' if(&bar==NULL)... mais le compilateur peut optimiser la déclaration de l'existence! Une référence valide ne peut jamais être NULLE, afin de le compilateur considère que la comparaison est toujours faux - c'est l'essence même d'un comportement indéfini.

La bonne façon de rester hors de l'ennui est pour éviter le déréférencement d'un pointeur NULL pour créer une référence. Voici un moyen automatisé pour accomplir cette tâche.

template<typename T>
T& ref(T* p)
{
    if (p == NULL)
        throw std::invalid_argument(std::string("NULL reference"));
    return *p;
}

MyClass * p = GetInstance();
Foo(ref(p));

110voto

Orion Edwards Points 54939

Vous avez oublié la partie la plus importante

membre d'accès avec des pointeurs utilise ->
membre d'accès avec des références utilise .

foo.bar est nettement supérieure à foo->bar de la même manière que vi est clairement supérieure à emacs :-)

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