Die Antwort hängt von Ihrem Standpunkt ab:
Wenn Sie nach dem C ++ - Standard urteilen, können Sie keine Nullreferenz erhalten, da Sie zuerst ein undefiniertes Verhalten erhalten. Nach diesem ersten Auftreten von undefiniertem Verhalten lässt der Standard zu, dass alles passiert. Wenn Sie also schreiben *(int*)0
, haben Sie bereits ein undefiniertes Verhalten, da Sie aus Sicht des Sprachstandards einen Nullzeiger dereferenzieren. Der Rest des Programms ist irrelevant. Sobald dieser Ausdruck ausgeführt wird, sind Sie aus dem Spiel.
In der Praxis können Nullreferenzen jedoch leicht aus Nullzeigern erstellt werden, und Sie werden es erst bemerken, wenn Sie tatsächlich versuchen, auf den Wert hinter der Nullreferenz zuzugreifen. Ihr Beispiel ist möglicherweise etwas zu einfach, da jeder gute Optimierungs-Compiler das undefinierte Verhalten erkennt und einfach alles wegoptimiert, was davon abhängt (die Nullreferenz wird nicht einmal erstellt, sondern wegoptimiert).
Diese Optimierung hängt jedoch vom Compiler ab, um das undefinierte Verhalten zu beweisen, was möglicherweise nicht möglich ist. Betrachten Sie diese einfache Funktion in einer Datei converter.cpp
:
int& toReference(int* pointer) {
return *pointer;
}
Wenn der Compiler diese Funktion sieht, weiß er nicht, ob der Zeiger ein Nullzeiger ist oder nicht. Es wird also nur Code generiert, der jeden Zeiger in die entsprechende Referenz verwandelt. (Übrigens: Dies ist ein Noop, da Zeiger und Referenzen im Assembler genau dasselbe Tier sind.) Nun, wenn Sie eine andere Datei user.cpp
mit dem Code haben
#include "converter.h"
void foo() {
int& nullRef = toReference(nullptr);
cout << nullRef; //crash happens here
}
Der Compiler weiß nicht, dass toReference()
der übergebene Zeiger dereferenziert wird, und geht davon aus, dass er eine gültige Referenz zurückgibt, die in der Praxis zufällig eine Nullreferenz ist. Der Aufruf ist erfolgreich, aber wenn Sie versuchen, die Referenz zu verwenden, stürzt das Programm ab. Hoffnungsvoll. Der Standard lässt zu, dass alles passiert, einschließlich des Aussehens von rosa Elefanten.
Sie fragen sich vielleicht, warum dies relevant ist, schließlich wurde das undefinierte Verhalten bereits im Inneren ausgelöst toReference()
. Die Antwort lautet Debugging: Nullreferenzen können sich wie Nullzeiger verbreiten und vermehren. Wenn Sie nicht wissen, dass Nullreferenzen vorhanden sein können, und lernen, diese nicht zu erstellen, müssen Sie möglicherweise einige Zeit damit verbringen, herauszufinden, warum Ihre Mitgliedsfunktion abstürzt, wenn nur versucht wird, ein einfaches altes int
Mitglied zu lesen (Antwort: die Instanz) Im Aufruf des Mitglieds befand sich eine Nullreferenz, ebenso this
wie ein Nullzeiger, und Ihr Mitglied wird so berechnet, dass es sich als Adresse befindet. 8).
Wie wäre es also mit der Suche nach Nullreferenzen? Du hast die Zeile gegeben
if( & nullReference == 0 ) // null reference
in deiner Frage. Nun, das wird nicht funktionieren: Gemäß dem Standard haben Sie undefiniertes Verhalten, wenn Sie einen Nullzeiger dereferenzieren, und Sie können keine Nullreferenz erstellen, ohne einen Nullzeiger zu dereferenzieren, sodass Nullreferenzen nur im Bereich des undefinierten Verhaltens existieren. Da Ihr Compiler möglicherweise davon ausgeht, dass Sie kein undefiniertes Verhalten auslösen, kann er davon ausgehen, dass es keine Nullreferenz gibt (obwohl er leicht Code ausgibt, der Nullreferenzen generiert!). Als solches sieht es die if()
Bedingung, kommt zu dem Schluss, dass es nicht wahr sein kann, und wirft einfach die gesamte if()
Aussage weg . Mit der Einführung von Verbindungszeitoptimierungen ist es offensichtlich unmöglich geworden, auf robuste Weise nach Nullreferenzen zu suchen.
TL; DR:
Nullreferenzen sind eine schreckliche Existenz:
Ihre Existenz scheint unmöglich (= nach Standard),
aber sie existieren (= nach dem generierten Maschinencode),
aber Sie können sie nicht sehen, wenn sie existieren (= Ihre Versuche werden optimiert),
aber sie können Sie trotzdem töten, ohne es zu wissen (= Ihr Programm stürzt an seltsamen Stellen ab oder schlimmer.
Ihre einzige Hoffnung ist, dass sie nicht existieren (= schreiben Sie Ihr Programm, um sie nicht zu erstellen).
Ich hoffe, das wird dich nicht verfolgen!