Beides (a)
und (b)
führen zu undefiniertem Verhalten. Es ist immer undefiniertes Verhalten, eine Mitgliedsfunktion über einen Nullzeiger aufzurufen. Wenn die Funktion statisch ist, ist sie auch technisch undefiniert, aber es gibt einige Streitigkeiten.
Das erste, was zu verstehen ist, ist, warum es undefiniertes Verhalten ist, einen Nullzeiger zu dereferenzieren. In C ++ 03 gibt es hier tatsächlich ein bisschen Mehrdeutigkeit.
Obwohl "das Dereferenzieren eines Nullzeigers zu undefiniertem Verhalten führt" in den Anmerkungen sowohl in §1.9 / 4 als auch in §8.3.2 / 4 erwähnt wird, wird dies niemals explizit angegeben. (Notizen sind nicht normativ.)
Man kann jedoch versuchen, es aus §3.10 / 2 abzuleiten:
Ein Wert bezieht sich auf ein Objekt oder eine Funktion.
Bei der Dereferenzierung ist das Ergebnis ein Wert. Ein Nullzeiger nicht auf ein Objekt. Wenn wir also den Wert l verwenden, haben wir ein undefiniertes Verhalten. Das Problem ist, dass der vorherige Satz nie angegeben wird. Was bedeutet es also, den Wert zu "verwenden"? Generieren Sie es einfach überhaupt oder verwenden Sie es im formaleren Sinne, um eine Wert-zu-Wert-Konvertierung durchzuführen?
Unabhängig davon kann es definitiv nicht in einen Wert umgewandelt werden (§4.1 / 1):
Wenn das Objekt, auf das sich der Wert bezieht, kein Objekt vom Typ T und kein Objekt von einem von T abgeleiteten Typ ist oder wenn das Objekt nicht initialisiert ist, hat ein Programm, das diese Konvertierung erfordert, ein undefiniertes Verhalten.
Hier ist es definitiv undefiniertes Verhalten.
Die Mehrdeutigkeit ergibt sich daraus, ob es sich um ein undefiniertes Verhalten zur Zurückhaltung handelt oder nicht, aber den Wert eines ungültigen Zeigers nicht verwendet (dh einen l-Wert erhalten, ihn aber nicht in einen r-Wert konvertieren). Wenn nicht, dann int *i = 0; *i; &(*i);
ist genau definiert. Dies ist ein aktives Problem .
Wir haben also eine strikte Ansicht "Dereferenzieren eines Nullzeigers, Erhalten eines undefinierten Verhaltens" und eine schwache Ansicht "Verwenden eines dereferenzierten Nullzeigers, Erhalten eines undefinierten Verhaltens".
Nun betrachten wir die Frage.
Ja, (a)
führt zu undefiniertem Verhalten. In der Tat, wenn this
dann null ist das Ergebnis unabhängig vom Inhalt der Funktion undefiniert.
Dies folgt aus §5.2.5 / 3:
Wenn E1
der Typ "Zeiger auf Klasse X" ist, wird der Ausdruck E1->E2
in die entsprechende Form konvertiert(*(E1)).E2;
*(E1)
wird zu undefiniertem Verhalten mit einer strengen Interpretation führen, und .E2
konvertiert es in einen r-Wert, wodurch es für die schwache Interpretation zu undefiniertem Verhalten wird.
Daraus folgt auch, dass es sich um ein undefiniertes Verhalten direkt aus (§9.3.1 / 1) handelt:
Wenn eine nicht statische Elementfunktion einer Klasse X für ein Objekt aufgerufen wird, das nicht vom Typ X oder von X abgeleitet ist, ist das Verhalten undefiniert.
Bei statischen Funktionen macht die strikte gegenüber der schwachen Interpretation den Unterschied. Genau genommen ist es undefiniert:
Auf ein statisches Element kann unter Verwendung der Klassenmitgliedszugriffssyntax verwiesen werden. In diesem Fall wird der Objektausdruck ausgewertet.
Das heißt, es wird so ausgewertet, als wäre es nicht statisch, und wir dereferenzieren erneut einen Nullzeiger mit (*(E1)).E2
.
Da dies E1
jedoch nicht in einem statischen Elementfunktionsaufruf verwendet wird, ist der Aufruf gut definiert, wenn wir die schwache Interpretation verwenden. *(E1)
ergibt sich ein lWert, die statische Funktion wird aufgelöst,*(E1)
verworfen und die Funktion aufgerufen. Es gibt keine Konvertierung von lWert in rWert, daher gibt es kein undefiniertes Verhalten.
In C ++ 0x bleibt ab n3126 die Mehrdeutigkeit bestehen. Seien Sie vorerst sicher: Verwenden Sie die strenge Interpretation.