Ich habe kürzlich folgenden Code gefunden:
%Vor% Der Code kompiliert, weil in C ++ Methoden nur Funktionen sind, die implizit einen Zeiger für 'this' übergeben und 'this' wie jeder andere Zeiger auf NULL gesetzt werden kann. Offensichtlich ist dieser Code verwirrend und schlechte Praxis, obwohl er nicht abstürzt; Es wäre ziemlich verwirrend, den Code im Debugger zu durchlaufen, zu sehen, dass ein NULL-Zeiger eine Methode aufgerufen hat und dann den erwarteten Absturz nicht sieht. Meine Frage ist: Verstößt es gegen den C ++ Standard, um SomeFooPtr->bar()
wo SomeFooPtr == NULL
aufzurufen?
Es kommt mir vor, dass es nicht möglich ist, weil der benutzerdefinierte Operator- & gt; gibt einen Zeiger zurück, was bedeutet, dass selbst wenn dieser Zeiger NULL ist, er definitiv nicht dereferenziert wurde (Dereferenzierung eines NULL-Zeigers, ich bin sicher, dass er vom Standard als illegal oder undefiniert angesehen wird). Auf der anderen Seite muss die Semantik von rohen Zeigern nicht unbedingt mit der Semantik von benutzerdefinierten Zeigern übereinstimmen - vielleicht operator- & gt; auf ihnen wird als Dereferenz betrachtet, obwohl der Compiler keine generiert.
Dies wird wahrscheinlich auf den meisten Systemen funktionieren, aber es ist Undefined Behavior. Quot der Standard:
5.2.5.3
Wenn
konvertiertE1
den Typ "Zeiger auf Klasse X" hat, wird der AusdruckE1->E2
in die äquivalente Form(*(E1)).E2
[...]
Und:
5.2.5.1
Ein Postfix-Ausdruck gefolgt von einem Punkt
.
oder einem Pfeil->
, optional gefolgt vom Schlüsselworttemplate
(14.8.1), gefolgt von einem id-Ausdruck , ist ein Postfix-Ausdruck. Der Postfix-Ausdruck vor dem Punkt oder Pfeil wird ausgewertet; 58) [...]58) Diese Auswertung findet selbst dann statt, wenn das Ergebnis nicht notwendig ist, um den Wert des gesamten Postfix-Ausdrucks zu bestimmen, beispielsweise wenn der ID-Ausdruck ein statisches Element bezeichnet.
Auswertung von *x
wobei x
ein Null-Zeiger ist, führt zu undefiniertem Verhalten, also ist Ihr eindeutig ein Fall von UB, bevor die Funktion überhaupt eingegeben wird.
Dieser Test ist fehlerhaft, auch wenn die Dereferenzierung kein UB ist. Es bricht, wenn dies - Anpassungen für die Mehrfachvererbung in das Spiel kommen:
%Vor%gibt hier "sicher" aus.
Es ist UB. Ein guter Weg, um es zum Absturz zu bringen, besteht darin, es als Basisklasse einer abgeleiteten Klasse zu verwenden, die mehrfache Vererbung verwendet. YMMV.
Es spielt keine Rolle, ob es legal ist, es ist verwirrend für den Leser. In der Implementierung, in der dieser Code funktioniert, wird auf die vtable nach Typ zugegriffen, sicherlich nicht nach Objekt.
Darüber hinaus erwarte ich, dass dieser Code für einen Konstruktorfehler verwendet wurde, der eine Vielzahl von Problemen anderswo verdecken würde. Konstruktorfehler sollten korrekt behandelt werden, nicht mit einem ekligen Kludn wie im Beispiel.