Quelles sont les différences entre un pointeur de variable et une variable de référence en C++?
Je sais références sont sucre syntaxique, donc le code est plus facile à lire et à écrire.
Mais quelles sont les différences?
Résumé des réponses et des liens ci-dessous:
- Un pointeur peut être assignée à n'importe quel nombre de fois tandis qu'une référence ne peut pas être ré-attribuée après la liaison.
- Pointeurs point de nulle part (
NULL
), tandis que la mention se réfère toujours à un objet. - Vous ne pouvez pas prendre l'adresse d'une référence comme vous le pouvez avec des pointeurs.
- 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 faire de l'arithmétique des pointeurs sur elle 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 peut
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
dei
en ce stockage.
Donc, un pointeur et une référence à la fois utiliser 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 pour fournir des informations utiles et l'auto-documentation des interfaces.
- Utiliser des pointeurs pour la mise en œuvre d'algorithmes et structures de données.
Lecture intéressante:
- Mon préféré de tous les temps C++ FAQ lite.
- Références vs Pointeurs.
- Une Introduction aux Références.
- Références et const.
- Une référence locale (c'est à dire, qui n'est pas dans une structure ou une classe) n'est pas nécessairement une allocation de stockage. Vous pouvez dire à cause de la sizeof différence entre sizeof(int &) et sizeof(struct { int &x; }).
- Je pense que le point 2 doit être "Un pointeur est autorisé à être NULLE, mais une référence n'est pas. Seulement incorrect code peut créer une référence NULL et son comportement n'est pas défini."
- Les pointeurs sont juste un autre type d'objet, et comme n'importe quel objet en C++, il peut être une variable. Références sur l'autre main ne sont jamais des objets, seules les variables.
- Cette compile sans mise en garde:
int &x = *(int*)0;
sur gcc. On peut, en effet, point à la valeur NULL. - Je ne suis pas sûr que je suis d'accord que "les références sont sucre syntaxique". Comment feriez-vous pour la conception de copier les constructeurs dans votre langue si vous n'avez pas de références?
- Sans doute on pourrait prendre l'adresse de référence, comme le langage adopté dans la mise en œuvre de l'opérateur d'affectation, c'est à dire
T& T::operator=(const T& rhs) { if (this == &rhs) return *this; ... }
. - aussi utile lien
- Je ne me sens pas qualifié pour modifier le "clarifier un malentendu" une partie de cette question, mais je pense qu'il doit être observé que si
int i
vit dans un registre pour l'ensemble de sa vie, la référence n'est probablement pas un pointeur, il suffit simplement de alias le même registre. - de référence est un alias de la variable
- Les références ne sont pas seulement sucre syntaxique: ils sont TOUJOURS dans un état. Ceci est renforcé par le compilateur. Les pointeurs ont pas cette garantie.
- J'aime la façon dont la première phrase est une totale illusion. Les références ont leur propre sémantique.
- Non, ce n'est pas correct. C'est une référence à ce que l'emplacement de la mémoire. La référence elle-même est valide. Accéder à ce qu'il y a bien - n'est pas défini.
- bien sûr, pour y arriver, vous déréférencé un pointeur null. . .qui est lui-même défini. . .
- Cette question montre l'arithmétique des pointeurs être fait sur une référence ("
&obj + 5
"). N'est-ce pas briser aliasing hypothèses, où le site d'appel suppose qu'une fonction appelée ne va pas faire un tel calcul. Ainsi, la signification de référence de l'arithmétique est UB? - Pointeur fondamentalement stocke l'adresse de son pointee.
- int *p = NULL; int &r=*p; référence vers NULL; if(r){} -> boOm 😉
- Non, que prend l'adresse de la référence de la cible. Lire de nouveau: Une référence est un alias vers un autre objet. (Sauf au stade de la création,) sa sémantique est entièrement identique à si vous avez utilisé le nom d'origine.
- Je ne dirais pas que les références sont mis en œuvre comme les pointeurs en C++, ils sont deux différentes abstractions pour l'adresse d'un objet. Penser comment le matériel fonctionne: dans le matériel, vous n'avez pas de "pointeurs", vous avez les registres, la mémoire et les instructions qu'ils opèrent sur les registres et la mémoire.
- J'aime à imaginer que les variables sont des gens lors d'une fête, puis un pointeur est quelqu'un qui va autour de leur doigt normalement destiné à quelqu'un d'autre et qui c'est peut être changé et, dans certains cas, le quelqu'un d'autre qui quitte la partie et ne peut plus se faire remarquer (hors de portée) ou assassiné (détruit, c'est un mauvais parti!), en d'autres occasions, le pointeur de la personne peut être fait le point d'une nouvelle personne (valeur modifiée) ou le sol (à 0,
nullptr
etc.). En comparaison, une variable de référence est un nouveau nom insigne qu'une personne peut mettre sur eux-mêmes (dont un pointeur peut utiliser aussi bien!) a pointer and a reference both occupy the same amount of memory
- ce qui est faux. Pointeur vers une fonction virtuelle peut occuper plus de mémoire qu'une référence.- Suis-je le seul qui pense que les pointeurs sont plus faciles à lire et ils permettent de préciser le code plus de références?
- Un point très important: le programmeur doit gérer la mémoire de pointeurs, mais pas de références.
- Un pointeur peut être nulle, c'est à dire assumer une valeur qui n'est manifestement pas le point de tout objet ou de la fonction. D'autre part, une référence null ne peut pas exister dans un programme bien défini, parce que la seule façon de créer une telle référence serait de le lier à l'objet ou la fonction obtenue par un déréférencement d'un pointeur null, ce qui provoque un comportement indéfini.
- De référence ne peut pas être réinstaller. A A, c; A& b = a; b=c ne fonctionnera pas.
- pas de travail" en fait cela dépend de ce que vous pensez que le code pour le faire
- fbb-git.github.io/cppannotations/cppannotations/html/... Peut-être d'intérêt trop et aussi, éventuellement, fbb-git.github.io/cppannotations/cppannotations/html/... - Le C++ Annotations qui est utile pour les programmeurs C - pour ce qu'il pourrait être intéressant est peut-être d'intérêt pour certaines. Personnellement j'ai eu plusieurs très mauvaises réactions à C++ - le look est inesthétique pour moi, au plus haut degré, et c'est seulement une question de beaucoup d'autres ... donc je ne vais pas être en mesure d'ajouter plus de liens, mais ils sont peut-être utile ou intéressant pour certains.
- Avec l'accent mis sur la mise en œuvre, étant donné que les compilateurs de mettre en œuvre des références comme pure pointeurs, références sont juste différentes syntaxique d'objet dans la langue avec des propriétés différentes que des pointeurs dans la langue. Est-ce exact?
- Vous êtes à la référence à null, et ce qui est interdit par les règles de la langue. Ainsi, vous POUVEZ utiliser une référence nulle, de la même façon, vous POUVEZ tuer des gens: vous ne devriez pas. Vous pouvez également modifier une valeur de référence étant donné que vous casser la pile où la variable réside...
- Pas de. Les pointeurs occupe toujours la même (sauf si vous avez de PRÈS et de LOIN pointeurs comme 16 bits de code sur un 8086). La classe virtuelle est un supplément de pointeur (il occupe un peu plus), mais la taille du pointeur est défini par matériel et toujours le même, quel qu'il points de, généralement de la taille de l'architecture (32 bits (x86; 64 bits sur x86_64).
- Je parlais de la mise en œuvre en C++, pas sur le matériel/os de la conception. Je veux dire que sizeof de pointeur de fonction et sizeof de méthode virtuelle pointeur sera différent.
- Ils ne sont pas différents à tous. Le fait qu'une fonction est virtuelle ajoute une couche d'indirection, mais n'augmente pas la taille du pointeur. Et la mise en œuvre est toujours très attaché à ce que le matériel n'en bas (la taille du pointeur est donné par le MATÉRIEL). godbolt.org/z/BgXbPc
- Je parlais de ceci:
static_assert(sizeof(&Polymorphic::polymethod) == 2*sizeof(void*), "Error in size");
. L'anglais n'est pas ma langue maternelle, peut-être que j'ai mal compris quelque chose. - Ni ma langue maternelle, mais le fait est que
sizeof(&Polymorphic::polymethod) == 2*sizeof(void*)
mais aussisizeof(&Base::method) == 2*sizeof(void*)
. Il n'a rien à voir avec le polymorphisme, c'est que les fonctions de membre d'objets nécessitent plus de taille, car ils ne sont pas "juste des pointeurs" barbante langue astuces que vous en penser.
Vous devez vous connecter pour publier un commentaire.
Un pointeur peut être ré-attribuée:
Une référence ne peut, et doit être attribuée à l'initialisation:
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. Plus sur pile vs tas. Cela implique qu'il y est une vraie adresse de référence que le compilateur ne vais pas vous dire.
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.
Pointeur peut être attribué
nullptr
directement, tandis que la référence ne peut pas. Si vous essayez assez dur, et vous savez comment, vous pouvez faire de l'adresse de référencenullptr
. 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 contenirnullptr
.Pointeurs pouvez effectuer une itération sur un tableau, vous pouvez utiliser
++
pour aller à l'élément suivant qu'un pointeur pointant vers, et+ 4
pour 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.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->
pour accéder à ses membres alors que, d'une référence utilise un.
.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.
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)
Const références peuvent être liées à des temporaires. Les pointeurs ne peut pas (non sans une certaine indirection):
Ce fait
const&
plus sûr pour une utilisation dans les listes d'arguments et ainsi de suite.7)
ajoute à2)
est que que les références peuvent être mis en œuvre différemment dans une autre langue-implémentations?a
, pas la référencec
.int *y = &(int){12};
.(int){12}
est un composé littéral, non temporaireint printf( char const * format, ... )
). Références n', avec les résultats les plus inattendus si vous essayez...reference
a été introduit?Ce qui est une référence C++ (pour les programmeurs C)
Un 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 la
*
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 en 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 de la C++ FAQ:
Mais si une référence vraiment ont é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
À venir à partir 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.
const int& ri = int(0);
. Parfaitement valide le code, qui compile, et initialise une référence à un objet qui a une valeur null. En dehors de cela, vous ne pouvez pas initialiser une référence à une valeur de toute façon. Une simple référence n'a aucune valeur. Cela devrait sans doute être revu.ri
est initialisé à se référer à un temporaire de type int dont la durée de vie est prolongée. C'est exactement le cas de l'initialisation d'une référence à une valeur qui, plus tard, vous demande n'est pas possible. Il est également faux de dire qu'une référence n'a aucune valeur. Sa valeur est la valeur de l'objet visé.const int& r = *(int *)nullptr;
. C'est un comportement indéterminé sans diagnostic nécessaire; en fait le compilateur ne peut pas le refuser, sauf s'il peut être prouvé que tous les chemins d'exécution atteindre cette ligne.int(0)
ou(int)0
est exactement le même que0
, c'est à dire un entier ayant une valeur de zéro.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.
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 cela, sans
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 aux fins de cette question.const &
de liaison, et seulement lorsque la référence est hors de portée, le destructeur de la réel de type référencé (par rapport au type de référence, qui pourrait être une base) est appelée. Puisque c'est une référence, pas de tranchage aura lieu entre les deux.const &
peut prolonger la durée de vie d'un temporaire, pas une variable. Normalement temporaire de la durée de vie est simplement la pleine expression dans laquelle elle est produite, à moins que ceconst
-référencé, dans ce cas, on obtient la durée de vie de la variable de référence. (Copier/déplacer dans un nom de variable ne sont pas techniquement durée de vie de l'extension.)Animal x = fast ? getHare() : getTortoise()
puisx
sera le visage de la classique de découpage problème, alors queAnimal& x = ...
fonctionne correctement.Contrairement à l'opinion populaire, il est possible d'avoir une référence NULL.
Accordée, 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. Les références sont pas intrinsèquement sûr en C++!
Techniquement, c'est un référence non valide, pas une référence nulle. C++ ne prend pas en charge les références null comme un concept que vous pourriez trouver dans d'autres langues. Il existe d'autres types de références non valides ainsi. Tout référence non valide soulève le spectre de comportement indéfini, tout comme l'aide d'un pointeur non valide serait.
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.
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 jamais de sens que pour vérifier une référence null; par exemple, vous pouvez essayer
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, et il est gratuit pour éliminer lesif
clause de code mort - 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.
Pour un vieux de regarder ce problème de quelqu'un avec de meilleures compétences en écriture, voir Des Références Nulles de Jim Hyslop et Herb Sutter.
Pour un autre exemple des dangers de déréférencement d'un pointeur null voir Exposer un comportement non défini lors de la tentative de port code sur une autre plateforme par Raymond Chen.
1 < 0
, unint
contenant3.5
, une fonction qui lance des missiles. Si tout est possible, rien n'est remarquable.optional<T&>
.String s = null;
et je reçois une référence null à une chaîne. Depuis références peuvent être réaffectés en C#, cela est tout à fait raisonnable. En C++ les références vous ne pouvez pas être réaffectés donc une référence null serait inutile, et la langue ne fait aucune tentative pour le soutenir.optional<T&>
aurait été juste que. Sauf, qu'elle n'existe pas. Principalement en raison de limiter arbitrairement la référence sémantique, ce qui les rend très exotiques pour C++ valeur sémantique (comme indiqué dans le ce CppCon 2017 parler).r = 1
a un comportement indéterminé, et que le code du bois bien si elle est limitée à la première deux lignes. En fait la deuxième ligne,int & r = *p
, a un comportement indéterminé et peut provoquer un plantage (ou n'importe quoi d'autre), même sansr = 1
. En regardant vos commentaires, je pense que tu dois déjà le savoir, mais le texte actuel de votre réponse est susceptible d'induire en erreur une personne qui n'a pas déjà rendre compte de cela.En dehors de sucre syntaxique, une référence est un
const
pointeur (pas pointeur vers unconst
). Vous devez établir ce que l'on fait référence lorsque vous déclarez une variable de référence, et vous ne pouvez pas le changer plus tard.Mise à jour: maintenant que j'y pense un peu plus, il existe une différence importante.
Const pointeur de cible peut être remplacée par la prise de son adresse et à l'aide d'un const exprimés.
Une référence de la cible ne peut pas être remplacé en quelque sorte court de l'AC.
Cela devrait permettre au compilateur de ne plus l'optimisation d'une référence.
T* const
avec différents sucre syntaxique (qui arrive à éliminer un grand nombre de * et & à partir de votre code).int i; int const *pci = &i; /* implicit conv to const int* */ int *pi = const_cast<int*>(pci);
est OK.Vous avez oublié le plus important: la
membre d'accès avec des pointeurs utilise
->
membre d'accès avec des références utilise
.
foo.bar
est clairement supérieure àfoo->bar
de la même manière que vi est clairement supérieure à Emacs 🙂->
fournit des références à des pointeurs, tout comme avec le pointeur lui-même..
et->
a quelque chose à voir avec vi et emacs 🙂.
est mieux que d'utiliser->
, mais juste comme vi vs emacs, il est tout à fait subjective et vous ne pouvez pas prouver quoi que ce soit.
syntaxe est plus facile de port de votre C++, C#, la langue ont été à l'aide.Les références sont très similaires à des pointeurs, mais ils sont spécifiquement conçus pour être utiles à l'optimisation des compilateurs.
Comme un exemple:
Un compilateur optimisant peut se rendre compte que nous sommes accéder à un[0] et[1] tout un groupe. Il serait l'amour pour optimiser l'algorithme de:
De faire une telle optimisation, il faut prouver que rien ne peut changer de tableau[1] lors de l'appel. C'est assez facile à faire. je n'est jamais inférieur à 2, tableau[i] ne peut jamais se référer à tableau[1]. maybeModify() est donnée a0 comme référence (aliasing tableau[0]). Parce qu'il n'y a pas de "référence" de l'arithmétique, le compilateur vient de prouver qu'maybeModify n'est jamais l'adresse de x, et il a prouvé que rien ne change: tableau[1].
Il doit également prouver qu'il n'existe aucun moyen d'un futur appel pouvait lire/écrire un[0], alors que nous avons un registre temporaire copie dans a0. C'est souvent triviale à prouver, parce que dans de nombreux cas, il est évident que la référence n'est jamais stocké dans une structure permanente comme une instance de classe.
Maintenant faire la même chose avec des pointeurs
Le comportement est le même; seulement, maintenant, il est beaucoup plus difficile à prouver que maybeModify ne jamais modifier array[1], parce que nous avons déjà donné un pointeur; le chat est sorti du sac. Maintenant, il y a à faire, ce qui est beaucoup plus difficile la preuve: une analyse statique de maybeModify pour prouver qu'il n'écrit jamais &x + 1. Il doit également prouver qu'il n'a jamais enregistre un pointeur qui peut se référer à tableau[0], qui est tout aussi délicate.
Les compilateurs modernes sont de mieux en mieux à l'analyse statique, mais il est toujours agréable de les aider et à utiliser des références.
Bien sûr, sauf intelligente telles optimisations, des compilateurs en effet tour de références dans des pointeurs en cas de besoin.
EDIT: Cinq ans après la publication de cette réponse, j'ai trouvé une réelle différence technique où les références sont différentes que juste une façon différente de regarder la même aborder le concept. Les références peuvent modifier la durée de vie des objets temporaires dans une manière que les pointeurs ne peut pas.
Normalement temporaire des objets tels que celui créé par l'appel à
createF(5)
sont détruits à la fin de l'expression. Cependant, par la liaison de l'objet de référence,ref
, C++ permettra de prolonger la durée de vie de l'objet temporaire jusqu'à ce queref
est hors de portée.maybeModify
ne pas prendre l'adresse de tout ce qui est lié àx
est sensiblement plus facile que de prouver qu'un tas de l'arithmétique des pointeurs ne se produit pas.void maybeModify(int& x) { 1[&x]++; }
les autres commentaires ci-dessus sont à discuterEn fait, une référence n'est pas vraiment comme un pointeur.
Un compilateur garde "références" à des variables, associer un nom à une adresse en mémoire; c'est son travail de traduire un nom de variable à une adresse de mémoire lors de la compilation.
Lorsque vous créez une référence, vous devez seulement indiquer au compilateur que vous attribuer un autre nom à la variable du pointeur; c'est pourquoi les références ne peuvent pas "point à nulle", car une variable ne peut pas être, et ne pas l'être.
Les pointeurs sont des variables; ils contiennent l'adresse d'une autre variable, ou peut être null. L'important, c'est qu'un pointeur a une valeur, alors qu'à titre de référence seulement a une variable à laquelle il fait référence.
Maintenant quelques explications de code réel:
Ici, vous n'êtes pas créer une autre variable qui pointe vers
a
; vous êtes juste ajouter un autre nom pour le contenu de la mémoire contenant la valeur dea
. Ce mémoire a maintenant deux noms,a
etb
, et il peut être adressée à l'aide d'un nom.Lors de l'appel d'une fonction, le compilateur génère habituellement des espaces de mémoire pour les arguments pour être copié. La signature de la fonction définit les espaces qui doivent être créées et donne le nom qui doit être utilisé pour ces espaces. Déclarer un paramètre par référence indique au compilateur d'utiliser la variable d'entrée de l'espace de mémoire au lieu d'allouer un nouvel espace mémoire lors de l'appel de méthode. Il peut sembler étrange de dire que votre fonction sera de manipuler directement une variable déclarée dans l'appel de la portée, mais n'oubliez pas que lors de l'exécution de code compilé, il n'y a pas plus de portée; il est tout simplement à plat de la mémoire et de votre code de fonction peut manipuler toutes les variables.
Maintenant, il peut y avoir certains cas où votre compilateur ne peut pas être en mesure de connaître la référence lors de la compilation, comme lors de l'utilisation d'un extern variable. Ainsi, une référence peut ou ne peut pas être mis en œuvre comme un pointeur dans le code sous-jacent. Mais dans les exemples que je vous ai donné, il ne sera probablement pas être mis en œuvre avec un pointeur.
Une référence ne peut jamais être
NULL
.void Foo::bar() { virtual_baz(); }
que les erreurs de segmentation. Si vous n'êtes pas au courant que les références peuvent être null, vous pouvez pas de trace nulle retour à son origine.int *p = NULL; int &r=*p;
a été une bonne expérience, ils ont été tout simplement donner un exemple de comment une référence peut en effet êtreNULL
. L'UB, de couleur violette, les dragons n'apparaît pas jusqu'à ce que vous utilisation la référence nulle, tout comme l'UB n'est pas le cas avec les pointeurs null jusqu'à ce que vous "déréférencement du pointeur. Mais même si c'est UB, dans les deux cas, elle est assez bien prévu que l'UB entraînera un SIGSEGV ou d'accès à la mémoire exception, sauf si vous travaillez sur un système embarqué, dans ce cas, vous peut très bien être en train d'essayer d'accéder à quelque chose qui est vraiment à l'adresse 0.-O0
annule la sortie du programme! À la hausse des niveaux d'optimisation, nous ne pouvons même pas demander si l'adresse de référence est nulle, car l'optimiseur sait qu'aucune référence n'est autorisé à être null;&x != nullptr
sur une référencex
est une tautologie!Tout à la fois les références et les pointeurs sont utilisés pour accéder indirectement à une autre valeur, il y a deux différences importantes entre les références et les pointeurs. La première est qu'une référence se réfère toujours à un objet: C'est une erreur de définir une référence sans l'initialiser. Le comportement de la cession est la deuxième différence importante: l'Attribution d'une référence de l'objet dont la référence est lié; il ne permet pas de relier la référence à un autre objet. Une fois initialisée, une référence se réfère toujours à la même objet sous-jacent.
Tenir compte de ces deux fragments. Dans la première, nous assigner un pointeur vers un autre:
Après la cession, ival, l'objet adressée par pi reste inchangé. La cession des changements de la valeur de pi, le faisant pointer vers un objet différent. Considérons maintenant un programme similaire qui attribue deux références:
Cette mission changements ival, la valeur référencée par ri, et non pas la référence elle-même. Après la cession, les deux références tout de même consulter leurs objets d'origine, et la valeur de ces objets est maintenant le même que bien.
Il y a une différence sémantique qui peut paraître ésotérique, si vous n'êtes pas familier avec l'étude des langages de programmation en un résumé ou même universitaire de la mode.
Au plus haut niveau, l'idée de références, c'est qu'ils sont transparents "alias". Votre ordinateur peut utiliser une adresse pour les faire travailler, mais vous n'êtes pas censé vous inquiétez à ce sujet: vous êtes censés penser à eux comme "juste un autre nom" d'un objet existant et de la syntaxe en est le reflet. Ils sont plus stricts que les pointeurs de sorte que votre compilateur ne peut plus fiable de vous avertir lorsque vous vous apprêtez à créer une balançant de référence, que lorsque vous êtes sur le point de créer une balançant pointeur.
Au-delà de ça, il y a bien sûr quelques différences concrètes entre les pointeurs et les références. La syntaxe à utiliser est évidemment différente, et vous ne pouvez pas "re-siège" des références, des références à néant, ou ont des pointeurs vers des références.
Une référence est un alias pour une autre variable tandis que un pointeur détient l'adresse mémoire d'une variable. Les références sont généralement utilisés comme paramètres de la fonction, de sorte que l'objet passé n'est pas de la copie, mais l'objet lui-même.
Il n'a pas d'importance combien d'espace qu'il occupe, car vous ne pouvez pas voir n'importe quel effet secondaire (sans l'exécution de code) de tout l'espace qu'il faudrait jusqu'à.
D'autre part, une différence majeure entre les références et les pointeurs, c'est que temporaires affectés à const références vivre jusqu'à ce que la const de référence est hors de portée.
Par exemple:
sera d'impression:
C'est la langue mécanisme qui permet ScopeGuard de travail.
Ceci est basé sur la tutoriel. Ce qui est écrit rend plus clair:
Simplement de se rappeler que,
Qui plus est, nous pouvons nous référer à presque n'importe quel pointeur tutoriel, un pointeur est un objet qui est pris en charge par l'arithmétique des pointeurs qui rend pointeur de similaire à un tableau.
Regardez la déclaration suivante,
alias_Tom
peut être comprise comme unalias of a variable
(différents avectypedef
, qui estalias of a type
)Tom
. Il est également OK pour oublier la terminologie de cette déclaration est de créer une référence deTom
.nullptr
? Avez-vous réellement lu toute autre partie de ce thread, ou...?Une référence n'est pas un autre nom donné à la mémoire. C'est un immuable pointeur qui est automatiquement dé-référencé sur l'utilisation. En gros, ça revient à:
En interne devient
const
pointeur. De flexibilité, ce qui ne prouve pas qu'il existe une différence entre une référence et un pointeur.Je utiliser des références, à moins que j'ai besoin de l'un de ces:
Pointeurs Null peut être utilisé comme un
sentinelle de la valeur, souvent un moyen peu coûteux de
éviter les surcharges de fonctions ou l'utilisation de
un bool.
Vous pouvez faire de l'arithmétique sur un pointeur.
Par exemple,
p += offset;
&r + offset
oùr
a été déclarée à titre de référenceUne référence à un pointeur est possible en C++, mais l'inverse n'est pas possible signifie un pointeur vers une référence n'est pas possible. Une référence à un pointeur fournit un nettoyeur de syntaxe pour modifier le pointeur.
Regardez cet exemple:
Et de considérer la version C du programme ci-dessus. En C, vous devez utiliser pointeur de pointeur (plusieurs indirection), et il conduit à la confusion et le programme peut sembler compliqué.
Visitez la page suivante pour plus d'informations sur la référence de pointeur:
Comme je l'ai dit, un pointeur vers une référence n'est pas possible. Essayez le programme suivant:
Il ya une différence fondamentale entre les pointeurs et les références que je n'ai pas vu quelqu'un avait mentionné: références de l'activer par référence à la sémantique dans les arguments de la fonction. Les pointeurs, même si elle n'est pas visible au premier abord ne sont pas: ils ne fournissent passer-par-valeur sémantique. Cela a été très bien décrit dans cet article.
Ce qui concerne,
&rzej
Au risque d'ajouter à la confusion, je tiens à jeter un peu de l'entrée, je suis sûr que ça dépend de la façon dont le compilateur met en œuvre les références, mais dans le cas de la gcc à l'idée qu'une référence ne peut pointer que vers une variable sur la pile n'est pas correcte, prenez cet exemple:
Qui sort ce:
Si vous remarquez même les adresses mémoire sont exactement les mêmes, ce qui signifie la référence est correctement pointant vers une variable sur le tas! Maintenant, si vous voulez vraiment obtenir bizarre, cela fonctionne aussi:
Qui sort ce:
Par conséquent, une référence EST un pointeur sous le capot, ils sont tous deux à seulement stocker une adresse de mémoire, où l'adresse est orientée à l'est hors de propos, que pensez-vous qui se passerait si j'ai appelé std::cout << str_ref; APRÈS l'appel de supprimer &str_ref? Bon, évidemment, ça compile bien, mais provoque une erreur de segmentation lors de l'exécution, car il n'est plus pointant vers une variable valide, nous avons essentiellement d'une rupture de la référence qui existe toujours (jusqu'à ce qu'il tombe hors de la portée), mais il est inutile.
En d'autres termes, une référence est rien, mais un pointeur le pointeur de la mécanique disparaît, le rendant plus sûr et plus facile à utiliser (pas accidentelle pointeur de maths, pas de mélange jusqu' '.' et '->', etc.), en supposant que vous n'essayez pas de bêtises comme mes exemples ci-dessus 😉
Maintenant indépendamment de la façon dont un compilateur traite les références, il toujours avoir une sorte de pointeur sous le capot, car une référence doit se référer à une variable spécifique à une adresse de mémoire pour qu'il fonctionne comme prévu, il n'y a pas moyen de contourner cela (d'où le terme de "référence").
La seule grande règle importante à retenir avec des références, c'est qu'ils doivent être définis au moment de la déclaration (à l'exception d'une référence dans un en-tête, dans ce cas, il doit être définie dans le constructeur, après que l'objet c'est contenue dans le construit, il est trop tard pour le définir).
Rappelez-vous, mes exemples ci-dessus ne sont que des exemples démontrant ce qu'est une référence est, vous ne voulez pas utiliser une référence dans ces manières! Pour une utilisation correcte d'une référence il y a beaucoup de réponses ici déjà qui a frappé le clou sur la tête
Une autre différence est que vous pouvez avoir des pointeurs vers un type void (et cela signifie pointeur à rien), mais les références à vide sont interdits.
Je ne peux pas dire que je suis vraiment heureux avec cette différence particulière. Je préfère de beaucoup qu'il serait autorisé avec le sens de la référence à quoi que ce soit avec une adresse et le même comportement pour les références. Elle permettrait de définir un certain nombre d'équivalents de fonctions de la bibliothèque C comme memcpy l'aide de références.
La réponse directe
Ce qui est une référence en C++? Certains instance spécifique de type n'est pas un objet de type.
Ce qu'est un pointeur en C++? Certains instance spécifique de type est un type d'objet.
De l'ISO C++ définition de type d'objet:
Il peut être important de savoir, le type d'objet est un haut-niveau de la catégorie de l'univers de type en C++. Référence est également un haut niveau de la catégorie. Mais le pointeur ne l'est pas.
Les pointeurs et les références sont mentionnés ensemble dans le contexte de composé de type. Cela est essentiellement dû à la nature de la déclaration de syntaxe héritée de (et) C, qui n'a pas de références. (D'ailleurs, il y a plus d'un type de demande de déclaration de références depuis C++ 11, tandis que les pointeurs sont encore "unityped":
&
+&&
vs*
.) Si la rédaction d'un langage spécifique par "extension", avec le même style de C dans ce contexte, c'est assez raisonnable. (Je vais encore affirmer que la syntaxe de declarators déchets syntaxiques expressivité beaucoup, rend à la fois les utilisateurs et les implémentations de la frustration. Ainsi, tous d'entre eux ne sont pas qualifiés pour être intégré dans un nouveau langage de conception. C'est un tout autre sujet sur les PL conception, cependant).Sinon, il est significatif que les pointeurs peut être qualifié comme l'une des sortes de types avec les références de l'ensemble. Ils partagent tout simplement trop peu de propriétés communes en plus de la syntaxe de la similitude, il n'ya donc pas besoin de les mettre ensemble dans la plupart des cas.
Note les déclarations ci-dessus ne mentionne que les "pointeurs" et "références" comme des types. Il y a quelques intéressés à des questions sur leur cas (comme les variables). Il y a aussi venir aussi beaucoup d'idées fausses.
Les différences de haut-niveau des catégories peut déjà révéler de nombreux de béton les différences ne sont pas liées à des pointeurs directement:
cv
qualificatifs. Les références ne peuvent pas.Un peu plus de règles spéciales sur les références:
&&
paramètres (comme le "transfert des références") sur la base de référence de l'effondrement des cours de paramètre de modèle déduction permettre "le transfert parfait" de paramètres.std::initializer_list
suit certaines règles similaires de référence durée de vie de l'extension. C'est une autre boîte de pandore.Les idées fausses
Sucre syntaxique
Techniquement, c'est simplement faux. Les références ne sont pas sucre syntaxique de toutes les autres fonctions en C++, parce qu'ils ne peuvent pas être exactement remplacé par d'autres fonctions, sans différences sémantiques.
(De la même manière, lambda-expressions sont pas sucre syntaxique de toutes les autres fonctionnalités en C++ car il ne peut pas être précisément simulée avec le "non spécifié" propriétés comme l'ordre de déclaration de la capture de variables, qui peut être important, car l'ordre d'initialisation de ces variables peuvent être importantes.)
C++ a seulement quelques types de sucres syntaxiques dans ce sens strict. Un exemple est (hérité de C) intégré (non surchargé) opérateur
[]
, qui est défini exactement les mêmes propriétés sémantiques des formes spécifiques de la combinaison de plus de opérateur unaire*
et binaire+
.De stockage
La déclaration ci-dessus est tout simplement faux. Pour éviter de tels malentendus, regardez la norme ISO C++ règles:
De [intro.objet]/1:
De [dcl.ref]/4:
Noter que ce sont sémantique propriétés.
Pragmatique
Même que les pointeurs ne sont pas suffisamment qualifiés pour être mis ensemble avec des références dans le sens de la langue de la conception, il ya encore quelques arguments rendant discutable de faire de choix entre eux dans d'autres contextes, par exemple, lorsqu'ils font des choix sur les types de paramètre.
Mais ce n'est pas toute l'histoire. Je veux dire, il ya plus de choses que des pointeurs vs les références que vous avez à considérer.
Si vous n'avez pas à tenir sur ces over-choix précis, dans la plupart des cas, la réponse est courte: vous n'avez pas la nécessité d'utiliser des pointeurs, donc vous n'avez pas. Les pointeurs sont généralement assez mauvais, car elles impliquent beaucoup trop de choses que vous n'avez pas à attendre et ils vont s'appuyer sur trop d'hypothèses implicites de saper la maintenabilité et de la (même) la portabilité du code. Inutilement en s'appuyant sur les pointeurs est certainement un mauvais style, et il devrait être évité dans le sens de C++ moderne. Reconsidérer votre but et vous trouverez enfin que pointeur est à la une de la dernière sortes dans la plupart des cas.
&
type de référence que le 1er type de paramètre. (Et habituellement, il devrait êtreconst
qualifié.)&&
type de référence que le 1er type de paramètre. (Et normalement il devrait y avoir pas de qualificatifs.)operator=
spéciale les fonctions de membre exige que les types de référence similaire pour le 1er paramètre de copier/déplacer des constructeurs.++
nécessite mannequinint
.unique_ptr
etshared_ptr
(ou même avec homebrew par vous-même si vous en avez besoin pour être opaque), plutôt que brut de pointeurs.std::optional
, plutôt que brut de pointeurs.observer_ptr
dans la Bibliothèque Fondamentale TS.Les seules exceptions à cette règle ne peut pas être contourné dans le langage courant:
operator new
. (Cependant, cv-void*
est encore tout à fait différente et plus sûr par rapport à l'ordinaire de pointeurs d'objet, car elle exclut inattendu pointeur de l'arithmétique, sauf si vous êtes en s'appuyant sur certains non-conforme extension survoid*
comme GNU.)Donc, dans la pratique, la réponse est tellement évidente: en cas de doute, évitez les pointeurs. Vous devez utiliser des pointeurs seulement lorsqu'il y a très explicite raisons que rien d'autre n'est plus appropriée. Sauf quelques cas exceptionnels mentionnés ci-dessus, de tels choix sont presque toujours pas purement C++spécifiques (mais susceptible d'être la langue spécifique à l'implémentation). Ces instances peuvent être:
Langue neutralité mises en garde
Si vous venez de voir la question via certains résultat de recherche de Google (pas spécifique au C++), c'est très probablement au mauvais endroit.
Les références en C++ est assez "bizarre", car il n'est pas essentiellement de première classe: ils seront traités comme des objets ou des fonctions visées à donc ils n'ont aucune chance à l'appui de certaines premières opérations de classe comme étant l'opérande de gauche de l'accès des membres de l'opérateur indépendamment du type de l'objet. D'autres langues peuvent ou peuvent ne pas avoir les mêmes restrictions sur leurs références.
Les références en C++ ne sera probablement pas préserver le sens à travers les différentes langues. Par exemple, les références en général n'implique pas non null propriétés sur des valeurs comme ils l'ont dans le C++, donc, ces hypothèses peuvent ne pas fonctionner dans certaines autres langues (et vous allez trouver des contre-exemples assez facilement, par exemple, Java, C#, ...).
Il peut encore y avoir quelques propriétés communes entre les références dans différents langages de programmation en général, mais laissons cela pour certains d'autres questions dans la.
(Une note de côté: la question peut être important, plus tôt que les "C", semblables à des langues sont en cause, comme ALGOL 68 vs PL/I.)
Une autre utilisation intéressante de références est de fournir un argument par défaut d'un type défini par l'utilisateur:
La valeur par défaut de la saveur utilise la "liaison const référence à un temporaire' aspect de références.
Aussi, une référence qui est un paramètre à une fonction inline peuvent être traités différemment d'un pointeur.
De nombreux compilateurs lors de l'inlining le pointeur de la première version sera en fait la force d'une écriture de la mémoire (nous sommes à l'adresse explicitement). Cependant, ils quittent la référence dans un registre qui est plus optimal.
Bien sûr, pour les fonctions qui ne sont pas inline le pointeur et référence de générer le même code et c'est toujours mieux de passer intrinsèques par la valeur que par référence si elles ne sont pas modifiés et retourné par la fonction.
Ce programme peut aider à comprendre la réponse de la question. C'est un programme simple de référence "j" et un "pointeur ptr" pointant vers la variable "x".
Exécuter le programme et ont un look à la sortie et vous allez comprendre.
Aussi, de pièces de rechange 10 minutes et regardez cette vidéo: https://www.youtube.com/watch?v=rlJrrGV0iOg
Je me sens comme il est encore un autre point qui n'a pas été abordé ici.
Contrairement aux pointeurs, références sont syntaxiquement équivalent à l'objet auquel ils se réfèrent, c'est à dire une opération qui peut être appliquée à un objet de travaux de référence, et avec exactement la même syntaxe (l'exception est bien sûr l'initialisation).
Alors que cela peut sembler superficiel, je crois que cette propriété est cruciale pour un certain nombre de fonctionnalités C++, par exemple:
Modèles. Depuis les paramètres du modèle sont de canard tapé, propriétés syntaxiques d'un type est tout ce qui compte, ce sont souvent les même modèle peut être utilisé à la fois avec
T
etT&
.(ou
std::reference_wrapper<T>
qui repose toujours sur un cast implicitepour
T&
)Des modèles qui couvrent à la fois
T&
etT&&
sont encore plus fréquents.Lvalues. Considérons la déclaration
str[0] = 'X';
Sans références, il ne fonctionne que pour le c-cordes (char* str
). Le retour du personnage par référence permet à des classes définies par l'utilisateur pour avoir la même notation.Copie constructeurs. Du point de vue syntaxique il est logique de passer des objets à copier les constructeurs, et pas des pointeurs vers des objets. Mais il n'y a tout simplement aucun moyen pour un constructeur de copie pour prendre un objet par valeur d'un appel récursif de la même constructeur de copie. Cela laisse des références comme la seule option ici.
La surcharge de l'opérateur. Avec des références, il est possible d'introduire une indirection à un opérateur call - dire,
operator+(const T& a, const T& b)
tout en conservant la même notation infixe. Cela fonctionne aussi pour les régulièrement les fonctions surchargées.Ces points de conférer à une partie considérable de C++ et la bibliothèque standard, c'est donc tout à fait un grand bien de références.
Peut-être que certaines métaphores va aider;
Dans le cadre de votre bureau screenspace -
Il est très important de non-différence technique entre les pointeurs et les références: Un argument passé à une fonction par pointeur est beaucoup plus visible qu'un argument transmis à une fonction par des non-const de référence. Par exemple:
De retour dans C, un appel qui ressemble à
fn(x)
ne peut être passé par valeur, de sorte qu'il ne peut absolument pas modifierx
; pour modifier un argument que vous auriez besoin pour passer un pointeurfn(&x)
. Donc, si un argument n'est pas précédée par une&
tu savais qu'il ne serait pas modifiée. (Les converse,&
signifie modifié, n'était pas vrai parce que vous aurais parfois à passer de grands en lecture seule structures parconst
pointeur.)Certains prétendent que c'est une telle fonctionnalité utile lors de la lecture du code, que les paramètres de pointeur doit toujours être utilisé pour les paramètres modifiables plutôt que les non-
const
des références, même si la fonction ne demande jamais à unnullptr
. Qui est, ceux qui disent que les signatures de la fonction commefn3()
ci-dessus ne devraient pas être autorisés. Google C++ lignes directrices de style en sont un exemple.Différence entre pointeur et référence
Un pointeur peut être initialisé à 0 et une valeur de référence pas. En fait, une référence doit également se référer à un objet, mais un pointeur peut être le pointeur null:
Mais nous ne pouvons pas avoir
int& p = 0;
et aussiint& p=5 ;
.En fait pour le faire correctement, nous devons avoir déclarée et définie d'un objet lors de la première alors on peut faire une référence à cet objet, de sorte que la mise en œuvre correcte de la précédente code sera:
Un autre point important est que nous pouvons faire la déclaration du pointeur de la souris sans initialisation toutefois pas une telle chose peut être fait dans le cas de référence qui doit faire une référence toujours à la variable ou un objet. Cependant l'utilisation d'un pointeur est risqué donc, généralement, nous allons vérifier si le pointeur est en fait vers quelque chose ou pas. Dans le cas d'une référence pas une telle vérification est nécessaire, car nous savons déjà que la référence à un objet pendant que la déclaration est obligatoire.
Une autre différence est que le pointeur peut pointer vers un autre objet cependant de référence est toujours référence au même objet, prenons cet exemple:
Un autre point: Lorsque nous avons un modèle comme un modèle STL de ce genre d'un modèle de classe retournera toujours une référence, pas un pointeur, pour faciliter la lecture ou de l'attribution nouvelle valeur à l'aide de l'opérateur []:
const int& i = 0
.La différence est que les non-constante pointeur de variable(à ne pas confondre avec un pointeur constant) peut être changé à un certain moment pendant l'exécution du programme, nécessite pointeur de la sémantique à être utilisé(&,*) les opérateurs, alors que les références peuvent être définies lors de l'initialisation seulement(c'est pourquoi vous pouvez les mettre dans le constructeur de l'initialiseur liste seulement, mais d'une certaine manière pas d'autre) et l'utilisation ordinaire de la valeur accéder à la sémantique. Fondamentalement, les références ont été introduites pour permettre le soutien à la surcharge d'opérateurs comme je l'avais lu dans un très vieux livre. Comme quelqu'un l'a dit dans ce fil - pointeur peut prendre la valeur 0 ou la valeur que vous souhaitez. 0(NULL, nullptr) signifie que le pointeur est initialisé avec rien. C'est une erreur de déréférencement de pointeur null. Mais en fait, le pointeur peut contenir une valeur qui ne pointent pas vers une bonne mémoire. Les références à leur tour essayer de ne pas permettre à un utilisateur d'initialiser une référence à quelque chose qui ne peut pas être référencée en raison du fait que vous avez toujours fournir rvalue de type approprié pour elle. Bien qu'il existe beaucoup de manières de faire référence variable sera initialisée à un mauvais emplacement de la mémoire -, il est préférable pour vous de ne pas creuser ce profond dans les détails. Sur la machine à la fois pointeur et référence de travail uniformément via des pointeurs. Disons que, pour l'essentiel, les références sont à sucre syntaxique. références rvalue sont différents de ce qu'ils sont naturellement pile/tas d'objets.
J'ai toujours décider par cette règle à partir de C++ lignes Directrices de Base:
nullptr
, ou à l'aide de terminal objets, peut soutenir une bien meilleure solution, au lieu de permettrenullptr
comme arguments.J'ai une analogie pour les références et les pointeurs, penser à des références comme un autre nom pour un objet et des pointeurs comme l'adresse d'un objet.
Vous pouvez utiliser la différence entre les références et les pointeurs si vous suivez une convention pour le passage d'arguments à une fonction. Const références sont pour les données transmises dans une fonction, et des pointeurs de données passée d'une fonction. Dans d'autres langues, vous pouvez explicite le signaler aux mots-clés
in
etout
. En C++, vous pouvez déclarer (par convention) l'équivalent. Par exemple,L'utilisation de références comme des entrées et des pointeurs comme des sorties est la partie de la Google guide de style.
const
.Taryn♦ dit:
En fait, vous pouvez.
Je suis citant une réponse à une autre question:
À côté de toutes les réponses ici,
vous pouvez mettre en œuvre la surcharge d'opérateur à l'aide de références:
À l'aide de paramètres comme la valeur serait de créer des copies temporaires de l'original arguments et en utilisant des pointeurs ne serait pas appeler cette fonction en raison de l'arithmétique des pointeurs.