Ist es legal / wohldefiniertes C ++, eine nicht statische Methode aufzurufen, die nicht über einen Nullzeiger auf Member zugreift?

7

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.

    
Joseph Garvin 15.07.2010, 15:55
quelle

5 Antworten

13

Dies wird wahrscheinlich auf den meisten Systemen funktionieren, aber es ist Undefined Behavior. Quot der Standard:

  

5.2.5.3

     

Wenn E1 den Typ "Zeiger auf Klasse X" hat, wird der Ausdruck E1->E2 in die äquivalente Form (*(E1)).E2 [...]

konvertiert

Und:

  

5.2.5.1

     

Ein Postfix-Ausdruck gefolgt von einem Punkt . oder einem Pfeil -> , optional gefolgt vom Schlüsselwort template (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.

    
Thomas 15.07.2010, 16:15
quelle
7

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.

    
Nordic Mainframe 15.07.2010 16:34
quelle
1

Dies ist (jetzt alle zusammen) undefiniertes Verhalten . Für viele Compiler funktioniert es jedoch mit der zusätzlichen Einschränkung, dass die Methode nicht virtuell sein muss.

    
JSBձոգչ 15.07.2010 16:04
quelle
1

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.

    
Hans Passant 15.07.2010 16:04
quelle
1

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.

    
msw 15.07.2010 16:01
quelle

Tags und Links