Est référence null possible?
Est ce morceau de code valide (et de comportement défini)?
int &nullReference = *(int*)0;
G++ et clang++ compiler sans aucun avertissement, même lors de l'utilisation de -Wall
, -Wextra
, -std=c++98
, -pedantic
, -Weffc++
...
Bien sûr, la référence n'est pas réellement nulle, car elle ne sera pas accessible (ça voudrait dire déréférencement d'un pointeur null), mais nous n'avons pu vérifier si elle est null ou non par la vérification de son adresse:
if( & nullReference == 0 ) //null reference
- Pouvez-vous donner tous les cas où ce serait réellement utile? En d'autres termes, est-ce juste une question de théorie?
- Eh bien, sont des références toujours indispensable? Les pointeurs peuvent toujours être utilisés à leur place. Une telle référence null permet d'utiliser une référence aussi quand vous pourriez n'ont pas d'objet de référence. Ne sais pas comment sale, il est, mais avant de penser à elle, j'ai été intéressé sur sa légalité.
- Je pense que c'est désapprouvé
- "nous avons pu vérifier" - non, vous ne pouvez pas. Il existe des compilateurs qui tourner la déclaration en
if (false)
, l'élimination de la case, précisément parce que les références ne peut pas être nul, de toute façon. Mieux documentés version existe dans le noyau Linux, d'où une très similaires NULL chèque a été optimisé à: isc.sans.edu/diary.html?storyid=6820 - "l'une des principales raisons de l'utilisation d'une référence au lieu d'un pointeur est de vous libérer du fardeau d'avoir à tester pour voir si elle fait référence à un objet valide" cette réponse, à Défaut de lien, ça a l'air bien bon!!!
- oui c'est bien, mais certaines personnes vont faire de suicide si vous allez l'utiliser 🙂
Vous devez vous connecter pour publier un commentaire.
Les références ne sont pas des pointeurs.
8.3.2/1:
De 1,9/4:
Que Johannes dit supprimé réponse, il y a un doute à savoir si le "déréférencement d'un pointeur null" doit être déclaré catégoriquement à un comportement indéfini. Mais ce n'est pas l'un des cas qui soulèvent des doutes, puisqu'un pointeur null n'est certainement pas un "objet valide ou d'une fonction", et il n'y a pas de désir au sein du comité des normes d'introduire des références nulles.
&*p
commep
universellement, qui n'exclut pas de comportement indéfini (qui peut, par nature, "ont l'air de travailler"); et je suis en désaccord quetypeid
expression qui cherche à déterminer le type d'un "déréférencé pointeur null" fait déréférence le pointeur null. J'ai vu des gens prétendre sérieusement que&a[size_of_array]
ne peut pas et ne doit pas être invoqué, et de toute façon il est plus facile et sécuritaire de l'écrirea + size_of_array
.*p
désigne, lorsquep
est un pointeur null. C++ n'a pas la notion du vide lvalue, dont la question 232 voulait introduire.typeid
des travaux basés sur la syntaxe, à la place de la sémantique. C'est, si vous netypeid(0, *(ostream*)0)
vous ne ont un comportement non défini - pas debad_typeid
est garanti d'être lancé, même si vous passez une lvalue résultant d'un déréférencement de pointeur null point de vue sémantique. Mais du point de vue syntaxique au niveau supérieur, ce n'est pas un déréférencement, mais un opérateur virgule expression.typeid
est un moteur d'exécution de l'opérateur et je vois le problème...La réponse dépend de votre point de vue: les
Si vous juge par la norme C++, vous ne pouvez pas obtenir une référence null parce que vous obtenez un comportement indéfini premier. Après que la première occurrence d'un comportement indéfini, la norme permet à tout pour arriver. Ainsi, si vous écrivez
*(int*)0
, vous avez déjà un comportement indéfini comme vous l'êtes, à partir d'une langue standard point de vue, un déréférencement d'un pointeur null. Le reste du programme n'est pas pertinent, une fois que cette expression est exécutée, vous êtes hors de la partie.Cependant, dans la pratique, null références peuvent facilement être créés à partir de pointeurs nuls, et vous ne remarquerez pas jusqu'à ce que vous avez réellement essayez d'accéder à la valeur de derrière la référence null. Votre exemple est peut-être un peu trop simple, comme toute bonne optimisation du compilateur va voir le comportement non défini, et tout simplement d'optimiser loin tout ce qui en dépend (la référence nulle de ne pas même être créé, il sera optimisé loin).
Encore, que l'optimisation de l'écart dépend du compilateur pour prouver le comportement non défini, qui peut ne pas être possible de le faire. Prenez simplement cette fonction à l'intérieur d'un fichier
converter.cpp
:Lorsque le compilateur voit cette fonction, il ne sait pas si le pointeur est un pointeur null ou pas. Jusqu'à ce qu'il génère du code qui transforme n'importe quel pointeur dans la référence correspondante. (Btw: C'est un noop puisque les pointeurs et les références sont à l'exact même bête en assembleur.) Maintenant, si vous avez un autre fichier
user.cpp
avec le codele compilateur ne sait pas que
toReference()
sera déréférencer le pointeur passé, et supposons qu'il renvoie une référence valide, ce qui va arriver à être une référence null dans la pratique. L'appel réussit, mais lorsque vous essayez d'utiliser la référence, le programme se bloque. Avec de la chance. La norme permet à tout pour arriver, y compris l'apparition de ping des éléphants.Vous demandez peut-être pourquoi c'est pertinent, après tout, le comportement non défini a déjà été déclenché à l'intérieur de
toReference()
. La réponse est de débogage: Null références peuvent se propagent et se multiplient tout comme les pointeurs null faire. Si vous n'êtes pas au courant que des références nulles peuvent exister, et apprendre à éviter la création d'eux, vous peut passer du temps à essayer de comprendre pourquoi votre fonction membre semble se bloquer lorsqu'il essaye juste de lire un simple vieuxint
membre (réponse: l'exemple de l'appel de la membre a été une référence nulle, doncthis
est un pointeur null, et votre membre est calculée à être situé à l'adresse 8).Alors comment sur la vérification de références nulles? Vous vous êtes donné la ligne de
dans votre question. Eh bien, ça ne marchera pas: Selon le standard, vous avez un comportement indéfini si vous déréférencer un pointeur null, et vous ne pouvez pas créer une référence null sans déréférencement d'un pointeur null, null références n'existent qu'à l'intérieur du domaine de comportement indéfini. Depuis votre compilateur peut supposer que vous n'êtes pas déclencher un comportement indéfini, on peut supposer qu'il n'y a pas une telle chose comme une référence null (même si il est prêt à émettre un code qui génère des références nulles!). Comme tel, il voit le
if()
condition, conclut qu'il ne peut pas être vrai, et de simplement jeter l'ensemble duif()
déclaration. Avec l'introduction de la liaison optimisations, il est devenu plaine impossible de vérifier la nullité des références dans un robuste.TL;DR:
Null références sont en quelque sorte une horrible existence:
Leur existence semble impossible (= par la norme),
mais ils existent (= par le code machine généré),
mais vous ne pouvez pas les voir, s'ils existent (= vos tentatives seront optimisées loin),
mais ils peuvent vous tuer pas au courant de toute façon (= votre programme se bloque à d'étranges points, ou pire).
Votre seul espoir est qu'ils n'existent pas (= écrire votre programme de ne pas les créer).
J'espère qui va pas venir vous hanter!
Si votre intention était de trouver un moyen de représenter la valeur null dans une énumération d'objets singleton, alors c'est une mauvaise idée (de)référence null (C++11, nullptr).
Pourquoi ne pas déclarer static singleton objet qui représente la valeur NULL dans la classe comme suit et ajouter un cast-à-pointeur de l'opérateur qui renvoie nullptr ?
Edit: Corrigé plusieurs mistypes et a ajouté que si l'instruction dans main() pour tester le cast-à-pointeur de l'opérateur en fait de travail (dont j'ai oublié de.. mon mal) - le 10 Mars 2015 -
clang++ de 3,5 même avertit sur elle: