La risposta dipende dal tuo punto di vista:
Se giudichi in base allo standard C ++, non puoi ottenere un riferimento nullo perché ottieni prima un comportamento indefinito. Dopo quella prima incidenza di comportamenti indefiniti, lo standard permette che tutto accada. Quindi, se scrivi *(int*)0
, hai già un comportamento indefinito come sei, da un punto di vista standard del linguaggio, dereferenziando un puntatore nullo. Il resto del programma è irrilevante, una volta eseguita questa espressione, sei fuori dal gioco.
Tuttavia, in pratica, i riferimenti null possono essere facilmente creati da puntatori null e non te ne accorgerai finché non proverai effettivamente ad accedere al valore dietro il riferimento null. Il tuo esempio potrebbe essere un po 'troppo semplice, poiché qualsiasi buon compilatore di ottimizzazione vedrà il comportamento indefinito e ottimizzerà semplicemente tutto ciò che dipende da esso (il riferimento null non verrà nemmeno creato, sarà ottimizzato).
Tuttavia, l'ottimizzazione dipende dal compilatore per provare il comportamento indefinito, cosa che potrebbe non essere possibile fare. Considera questa semplice funzione all'interno di un file converter.cpp
:
int& toReference(int* pointer) {
return *pointer;
}
Quando il compilatore vede questa funzione, non sa se il puntatore è un puntatore nullo o meno. Quindi genera solo codice che trasforma qualsiasi puntatore nel riferimento corrispondente. (Btw: questo è un noop poiché puntatori e riferimenti sono la stessa identica bestia in assembler.) Ora, se hai un altro file user.cpp
con il codice
#include "converter.h"
void foo() {
int& nullRef = toReference(nullptr);
cout << nullRef; //crash happens here
}
il compilatore non sa che toReference()
dereferenzierà il puntatore passato e presume che restituisca un riferimento valido, che in pratica sarà un riferimento nullo. La chiamata riesce, ma quando si tenta di utilizzare il riferimento, il programma si blocca. Fiduciosamente. Lo standard consente che accada qualsiasi cosa, inclusa la comparsa di elefanti rosa.
Potresti chiederti perché questo è rilevante, dopo tutto, il comportamento indefinito è già stato attivato all'interno toReference()
. La risposta è il debug: i riferimenti nulli possono propagarsi e proliferare proprio come fanno i puntatori nulli. Se non sei consapevole che possono esistere riferimenti nulli e impari a evitare di crearli, potresti dedicare un po 'di tempo a cercare di capire perché la tua funzione membro sembra bloccarsi quando sta solo cercando di leggere un semplice vecchio int
membro (risposta: l'istanza nella chiamata del membro era un riferimento nullo, quindi this
è un puntatore nullo e il tuo membro viene calcolato per essere posizionato come indirizzo 8).
Allora che ne dici di controllare i riferimenti nulli? Hai dato la linea
if( & nullReference == 0 ) // null reference
nella tua domanda. Bene, questo non funzionerà: secondo lo standard, hai un comportamento indefinito se dereferenzia un puntatore nullo e non puoi creare un riferimento nullo senza dereferenziare un puntatore nullo, quindi i riferimenti nulli esistono solo all'interno del regno del comportamento indefinito. Poiché il compilatore può presumere che non si stia innescando un comportamento indefinito, può presumere che non esista un riferimento nullo (anche se emetterà prontamente codice che genera riferimenti nulli!). In quanto tale, vede la if()
condizione, conclude che non può essere vera e getta via l'intera if()
affermazione. Con l'introduzione delle ottimizzazioni del tempo di collegamento, è diventato semplicemente impossibile controllare i riferimenti nulli in modo affidabile.
TL; DR:
I riferimenti nulli sono in qualche modo un'esistenza orribile:
La loro esistenza sembra impossibile (= per lo standard),
ma esistono (= per il codice macchina generato),
ma non puoi vederli se esistono (= i tuoi tentativi saranno ottimizzati),
ma potrebbero comunque ucciderti inconsapevole (= il tuo programma si blocca in punti strani o peggio).
La tua unica speranza è che non esistano (= scrivi il tuo programma per non crearli).
Spero che non venga a perseguitarti!