
FAQ C++Consultez toutes les FAQ
Nombre d'auteurs : 34, nombre de questions : 368, derni�re mise � jour : 14 novembre 2021 Ajouter une question
Cette FAQ a �t� r�alis�e � partir des questions fr�quemment pos�es sur les forums de http://www.developpez.com et de l'exp�rience personnelle des auteurs.
Je tiens � souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne pr�tend pas non plus �tre compl�te. Si vous trouvez une erreur ou si vous souhaitez devenir r�dacteur, lisez ceci.
Sur ce, nous vous souhaitons une bonne lecture.
- Qu'est-ce qu'une r�f�rence ?
- Que se passe-t-il si on assigne une autre valeur � la r�f�rence ?
- Que se passe-t-il en cas de retour d'une r�f�rence lors de l'appel d'une fonction ?
- Comment faire pour modifier une r�f�rence de fa�on qu'elle d�signe un autre objet�?
- Quand utiliser des r�f�rences et quand utiliser des pointeurs ?
- Qu'est-ce qu'un handle sur un objet ? une r�f�rence ? un pointeur ? un pointeur sur un pointeur ?
Une r�f�rence est un alias, un nom alternatif pour un objet. Le principe � retenir est que tout se passe comme si c'�tait l'objet lui-m�me et non une r�f�rence sur lui.
Les r�f�rences sont souvent utilis�es lors du passage de param�tres, en particulier avec le mot-cl� const (r�f�rence constante : donc le param�tre pass� est non modifiable) afin de rendre l'appel � la fonction plus performant sur des objets volumineux. Sans le mot-cl� const l'usage d'une r�f�rence indique alors que le param�tre est modifi� par la fonction.
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // fonction qui �change i et j void swap(int& i, int& j) { int tmp = i; i = j; j = tmp; } int main() { int x = 1; int y = 2; swap( x, y ); // x = 2, y = 1 } |
Bon, maintenant, pensons aux r�f�rences du point de vue du programmeur. Au risque de provoquer la confusion en donnant une autre perspective voici comment les r�f�rences sont impl�ment�es en pratique. Au fond, une r�f�rence i vers un objet x est habituellement son adresse. Mais quand le programmeur fait un i++, le compilateur g�n�re du code qui incr�mente x. Typiquement, les bits d'adressage que le compilateur utilise pour acc�der � x sont inchang�s. Un programmeur C pensera qu'il s'agit du passage d'un pointeur, avec les variantes syntaxiques suivantes :
- D�placer le & de l'appelant � l'appel� ;
- Supprimer les notations *s.
En d'autres mots, un programmeur le consid�rera comme une macro pour (*p), o� p est un pointeur sur x (par ex., le compilateur d�r�f�rencerait automatiquement le pointeur : i++ serait transform� en (*p)++).
Note : m�me si une r�f�rence est souvent impl�ment�e en utilisant une adresse dans le langage d'assemblage g�n�r�, ne consid�rez pas les r�f�rences comme un pointeur � marrant � sur un objet. Une r�f�rence est l'objet. Ce n'est pas un pointeur sur l'objet, ni une copie de l'objet. C'est l'objet.
L'�tat du r�f�rent (le r�f�rent est l'objet auquel la r�f�rence se rapporte) est modifi�.
Le r�f�rent est la r�f�rence, donc toute modification faite � la r�f�rence est faite au r�f�rent. Au niveau du compilateur, une r�f�rence est une � lvalue �, c'est-�-dire qu'il peut appara�tre � la gauche d'un op�rateur d'affectation.
L'appel de fonction peut se trouver � la gauche d'un op�rateur d'assignation.
Cette possibilit� peut sembler �trange au premier abord. Par exemple, personne ne penserait que l'expression f() = 7; ait un sens. Par contre, si a est un objet de la classe Array, la plupart des gens trouveront que a[i] = 7; a un sens, m�me si a n'est qu'un appel de fonction cach� (c'est en fait l'appel de l'op�rateur Array::operator [](int), qui est l'op�rateur d'indexation de la classe Array)
Code C++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Array { public: int size() const; float& operator[] (int index); ... }; int main() { Array a; for (int i = 0; i < a.size(); ++i) a[i] = 7; // cette ligne appelle Array::operator[](int) ... } |
Ce n'est pas possible.
On ne peut pas s�parer le r�f�r� de sa r�f�rence.
Contrairement aux pointeurs, lorsqu'une r�f�rence est li�e � un objet, elle ne peut pas �tre r�affect�e � un autre objet. La r�f�rence en elle-m�me n'est pas un objet (elle n'a pas d'identit� : prendre l'adresse d'une r�f�rence retourne l'adresse du r�f�rent).
De ce point de vue, une r�f�rence est similaire � un pointeur constant
Code c++ : | S�lectionner tout |
int* const p
par opposition � un pointeur sur une constante
Code c++ : | S�lectionner tout |
const int* p
En d�pit d'une certaine ressemblance, ne confondez pas les r�f�rences et les pointeurs ; ce n'est pas du tout la m�me chose.
Lorsque l'on compare le code ex�cutable g�n�r� lors de l'utilisation d'un pointeur et celui g�n�r� lors de l'utilisation d'une r�f�rence, on remarque qu'il est strictement identique.
Cependant la r�f�rence a l'�norme avantage sur le pointeur d'apporter une garantie de non nullit�, et de respecter la constance.
De plus, on ne peut envisager de d�clarer une r�f�rence qu'en lui indiquant directement l'objet dont elle se fait l'alias.
Ainsi, alors que Type * ptr; sera accept�, Type & ref; sera refus�.
De plus, lorsque, dans une fonction, on r�cup�re un pointeur, on n'est pas toujours (rarement�?) assur� que ce pointeur est non NULL, il va donc falloir souvent le v�rifier par un
Code c++ : | S�lectionner tout |
if (mon_pointeur!=NULL) {...}
Non seulement, cela all�ge et simplifie le code, mais �galement il arrive que ce test suppl�mentaire p�se lourd en terme de vitesse d'ex�cution.
En ce qui concerne la constance, elle va s'appliquer, pour les pointeurs, diff�remment en fonction de l'endroit o� se trouve le mot cl� const voir

- que l'on ne peut pas modifier l'objet ;
- que l'on ne peut pas d�cider de se servir de la r�f�rence comme alias pour un autre objet.
En outre, il faut se souvenir que l'utilisation des pointeurs est �norm�ment associ�e � la gestion dynamique de la m�moire (cr�ation avec new ou new[] et destruction respectivement avec delete ou delete[]), et que la gestion dynamique de la m�moire est le champs de mines par excellence qu'il s'agit d'�viter autant que possible. Voir

Or, il faut comprendre que le C++ fournit, au travers des diff�rents conteneurs qu'il pr�sente ou au travers de sa classe string, tout ce qu'il faut pour �viter � l'utilisateur de g�rer dynamiquement la m�moire si ce n'est pas tout � fait indispensable (cf

Enfin, m�me si ce n'est qu'un d�tail, il faut avouer que le fait de garder exactement la m�me syntaxe lorsque l'on manipule une r�f�rence que lorsque l'on manipule l'objet lui-m�me est presque rassurant.
En conclusion, l'id�al en C++ sera toujours de manipuler des r�f�rences (�ventuellement constantes) partout o� c'est possible sans devoir avoir recours � l'op�rateur � & � (prendre l'adresse de) et de ne manipuler des pointeurs que lorsque l'on n'a vraiment pas le choix.
Les cas pour lesquels nous n'aurons pas le choix �tant�:
- Lorsqu'il s'agit de passer un argument optionnel ou pouvant ne pas exister, on passe alors un pointeur NULL�;
- Lorsqu'il s'agit d'avoir une r�f�rence vers un objet optionnel ou pouvant ne pas exister (on utilise alors un pointeur sur l'objet dont l'adresse initialis�e est NULL)�;
- Lorsque tu as besoin de cr�er un objet polymorphique et que le type de l'objet � cr�er se d�termine selon les circonstances�;
- Lorsque, confront� � une relation � conteneur � contenu �, le contenu doit disposer d'une r�f�rence sur le conteneur�;
- Lorsque l'on souhaitera pouvoir modifier l'objet auquel on se r�f�re.
Note : il existe

Note : malgr� la garantie qu'une r�f�rence ne soit pas nulle, il existe des cas o� elle peut r�f�rer � un objet qui a �t� d�truit ou d�plac�, son utilisation �tant d�s lors dangereuse. On pourra citer le cas du retour par r�f�rence d'un objet local :
Code c++ : | S�lectionner tout |
1 2 3 4 5 | Type& fonction() { Type tmp; return tmp; } // tmp est d�truit |
Le terme handle est utilis� pour d�signer n'importe quelle technique qui permet de manipuler un autre objet (un genre de pseudo pointeur g�n�ralis�). Ce terme est (volontairement) ambigu et peu pr�cis.
L'ambigu�t� est un avantage dans certains cas. Par exemple, au tout d�but du design vous ne serez peut-�tre pas pr�t � adopter une repr�sentation sp�cifique pour d�signer les handles. Vous ne serez peut-�tre pas s�r du choix � faire entre les simples pointeurs, les r�f�rences, les pointeurs de pointeurs, les r�f�rences de pointeurs, ou encore des tableaux indic�s, ou des tables de hachage, ou des bases de donn�es ou n'importe quelle autre technique. Si vous savez que vous aurez besoin de quelque chose qui identifiera de fa�on unique un objet, appelez cette chose un handle.
Si votre but final est de permettre � une portion de code d'identifier/rechercher un objet sp�cifique d'une classe d'un certain type (par ex. Fred), vous devrez passer un handle sur Fred � cette portion de code. Le handle peut �tre une cha�ne qui peut-�tre utilis�e comme une cl� dans une table de recherche bien connue. Par exemple, une cl� dans
Code c++ : | S�lectionner tout |
std::map<std::string,Fred>
ou
Code c++ : | S�lectionner tout |
std::map<std::string,Fred*>
ou encore un entier qui sera un indice dans un tableau du genre
Code c++ : | S�lectionner tout |
Fred* array = new Fred[maxNumFreds]
ou tout simplement un pointeur sur Fred, ou n'importe quoi d'autre.
Les d�butants pensent souvent en termes de pointeurs, mais en r�alit�, ils prennent un risque. Que se passe-t-il si l'objet Fred doit �tre d�plac� ? Comment savoir quand il est sans risque d'effacer l'objet Fred ? Que se passe-t-il si l'objet doit �tre s�rialis� ?
La plupart du temps, on aura tendance � ajouter de plus en plus de couches d'indirections pour g�rer ces cas de figure. Par exemple, le handle sur Fred devrait �tre un Fred **, o� le pointeur pointant sur Fred* est suppos� ne jamais �tre d�plac�, mais � un moment le pointeur doit �tre d�plac�, on met seulement � jour le pointeur sur Fred *. Ou vous d�cidez que le handle devient un entier d�signant l'objet Fred dans une table, etc.
Le fait est que nous utilisons le mot handle tant que nous ne savons pas le d�tail de ce que nous allons faire.
Une autre circonstance dans laquelle nous utilisons le mot handle est quand on pr�f�re rester vague au sujet de ce que nous avons d�j� fait (on utilise parfois le terme ��cookie�� pour cela, par ex. � Le programme passe un cookie qui est utilis� pour identifier de fa�on unique l'objet Fred ad�quat �). La raison pour laquelle nous voulons (parfois) rester vague est de minimiser les effets de bord si les d�tails d'impl�mentations devaient changer. Par exemple, si quelqu'un change le handle qui �tait une cha�ne qui servait � faire une recherche dans une liste de hachage en un entier qui sert � indicer une table, cela pourrait causer le changement de dizaines de milliers de lignes de code.
Pour faciliter la maintenance quand les d�tails de repr�sentation d'un handle changent (ou tout simplement pour rendre le code plus lisible), nous encapsulerons le handle dans une classe. Cette classe surchargera souvent les op�rateurs -> et * (comme le handle agit comme un pointeur, il semble logique qu'il ressemble � un pointeur).
Proposer une nouvelle r�ponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plut�t sur le forum de la rubrique pour �aLes sources pr�sent�es sur cette page sont libres de droits et vous pouvez les utiliser � votre convenance. Par contre, la page de pr�sentation constitue une �uvre intellectuelle prot�g�e par les droits d'auteur. Copyright � 2025 Developpez Developpez LLC. Tous droits r�serv�s Developpez LLC. Aucune reproduction, m�me partielle, ne peut �tre faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'� trois ans de prison et jusqu'� 300 000 � de dommages et int�r�ts.