La réponse dépend de votre point de vue:
Si vous jugez par le standard C ++, vous ne pouvez pas obtenir une référence nulle car vous obtenez d'abord un comportement non défini. Après cette première incidence de comportement indéfini, la norme permet que tout se passe. Donc, si vous écrivez *(int*)0
, vous avez déjà un comportement indéfini car vous êtes, d'un point de vue standard du langage, en déréférençant un pointeur nul. Le reste du programme n'est pas pertinent, une fois cette expression exécutée, vous êtes hors du jeu.
Cependant, en pratique, les références nulles peuvent facilement être créées à partir de pointeurs nulles et vous ne le remarquerez pas tant que vous n'aurez pas réellement essayé d'accéder à la valeur derrière la référence null. Votre exemple est peut-être un peu trop simple, car tout bon compilateur d'optimisation verra le comportement indéfini et optimisera simplement tout ce qui en dépend (la référence nulle ne sera même pas créée, elle sera optimisée).
Pourtant, cette optimisation dépend du compilateur pour prouver le comportement non défini, ce qui peut ne pas être possible. Considérez cette fonction simple dans un fichier converter.cpp
:
int& toReference(int* pointer) {
return *pointer;
}
Lorsque le compilateur voit cette fonction, il ne sait pas si le pointeur est un pointeur nul ou non. Il génère donc simplement du code qui transforme n'importe quel pointeur en référence correspondante. (Btw: c'est un noop puisque les pointeurs et les références sont exactement la même bête dans l'assembleur.) Maintenant, si vous avez un autre fichier user.cpp
avec le code
#include "converter.h"
void foo() {
int& nullRef = toReference(nullptr);
cout << nullRef; //crash happens here
}
le compilateur ne sait pas que toReference()
va déréférencer le pointeur passé et suppose qu'il retourne une référence valide, qui se trouvera être une référence nulle en pratique. L'appel réussit, mais lorsque vous essayez d'utiliser la référence, le programme se bloque. J'espère. La norme permet que tout se passe, y compris l'apparition d'éléphants roses.
Vous pouvez vous demander pourquoi c'est pertinent, après tout, le comportement indéfini a déjà été déclenché à l'intérieur toReference()
. La réponse est le débogage: les références nulles peuvent se propager et proliférer comme le font les pointeurs nuls. Si vous n'êtes pas conscient que des références nulles peuvent exister et que vous apprenez à éviter de les créer, vous pouvez passer un certain temps à essayer de comprendre pourquoi votre fonction membre semble planter quand elle essaie simplement de lire un ancien int
membre (réponse: l'instance dans l'appel du membre était une référence nulle, de même this
qu'un pointeur nul, et votre membre est calculé pour être localisé en tant qu'adresse 8).
Alors, que diriez-vous de vérifier les références nulles? Vous avez donné la ligne
if( & nullReference == 0 ) // null reference
dans votre question. Eh bien, cela ne fonctionnera pas: selon la norme, vous avez un comportement non défini si vous déréférencer un pointeur nul, et vous ne pouvez pas créer une référence null sans déréférencer un pointeur nul, donc les références nulles n'existent que dans le domaine du comportement non défini. Puisque votre compilateur peut supposer que vous ne déclenchez pas de comportement indéfini, il peut supposer qu'il n'y a pas de référence nulle (même s'il émettra facilement du code qui génère des références nulles!). En tant que tel, il voit la if()
condition, conclut que cela ne peut pas être vrai et jette simplement la if()
déclaration entière . Avec l'introduction des optimisations de temps de liaison, il est devenu tout à fait impossible de vérifier les références nulles de manière robuste.
TL; DR:
Les références nulles sont en quelque sorte une existence horrible:
Leur existence semble impossible (= par le standard),
mais elles existent (= par le code machine généré),
mais vous ne pouvez pas les voir si elles existent (= vos tentatives seront optimisées),
mais elles peuvent vous tuer de toute façon inconscient (= votre programme plante à des moments bizarres, ou pire).
Votre seul espoir est qu'ils n'existent pas (= écrivez votre programme pour ne pas les créer).
J'espère que cela ne vous hantera pas!