Zugreifen auf statisches Element durch ungültigen Zeiger: garantiert "arbeiten"? [Duplikat]

8

Einrichtung

Gegeben dieser benutzerdefinierte Typ:

%Vor%

und die erforderliche Definition irgendwo sinnvoll platziert:

%Vor%

Folgendes ist die kanonische Methode, um den Wert von int in stdout zu streamen:

%Vor%

Kontrolle

Das Folgende ist (natürlich) aufgrund einer Instanz von T nicht vorhanden:

%Vor%

Frage

Betrachte nun den schrecklichen und bösen und schlechten folgenden Code:

%Vor%

Die Dereferenzierung von ptr ist ungültig, wie oben angegeben. Auch wenn hier keine physikalische Speicherdereferenzierung stattfindet, glaube ich, dass es immer noch als eins zählt und den obigen Code UB macht. Oder ... geht das?

14882: 2003 5.2.5 / 3 gibt explizit an, dass a->b in (*(a)).b konvertiert wird und dass:

  

Der Postfix-Ausdruck vor dem Punkt oder Pfeil wird ausgewertet;   Diese Auswertung findet selbst dann statt, wenn das Ergebnis nicht erforderlich ist, um den Wert des gesamten Postfix-Ausdrucks zu bestimmen, z. B. wenn der ID-Ausdruck ein statisches Element bezeichnet.

Aber es ist nicht klar, ob "Bewertung" hier eine tatsächliche Dereferenzierung beinhaltet. Tatsächlich scheinen weder 14882: 2003 noch n3035 explizit zu sagen, ob der Zeigerausdruck bei statischen Elementen mit einem Zeiger auf eine gültige Instanz ausgewertet werden sollte.

Meine Frage ist, wie ungültig ist das? Ist es wirklich spezifisch durch den Standard verboten (obwohl es keine physische Dereferenzierung gibt), oder ist es nur eine Eigenart der Sprache, mit der wir wahrscheinlich davonkommen können? Und selbst wenn es verboten ist, in welchem ​​Umfang können wir erwarten, dass GCC / MSVC / Clang es trotzdem sicher behandelt?

Mein g ++ 4.4 scheint Code zu produzieren, der niemals versucht, den [invalid] this -Zeiger auf den Stack zu schieben, wenn die Optimierungen ausgeschaltet sind.

BTW Wenn T polymorph wären, würde das keinen Einfluss darauf haben, da statische Member nicht virtuell sein können.

    
Lightness Races in Orbit 09.03.2011, 16:29
quelle

3 Antworten

10
  

Es ist nicht klar, ob "Bewertung" hier eine tatsächliche Dereferenzierung beinhaltet.

Ich lese "Auswertung" hier als "der Teilausdruck wird ausgewertet." Das würde bedeuten, dass das unäre * ausgewertet wird und Sie die Indirektion über einen Nullzeiger ausführen, was zu undefiniertem Verhalten führt.

Dieses Problem (Zugriff auf ein statisches Element über einen Nullzeiger) wird in einer anderen Frage diskutiert, Während die Member-Funktionen speziell behandelt werden, sehe ich keinen Grund Diese Datenelemente sind in dieser Hinsicht unterschiedlich. Es gibt eine gute Diskussion über das Thema dort.

Es wurde ein Fehler in Bezug auf den C ++ Standard gemeldet, der fragt: "Ist der Aufruf der Funktion statischer Member über den Nullzeiger undefiniert?" (Siehe CWG Defect 315 ) Dieser Fehler ist geschlossen und seine Auflösung steht fest dass es zulässig ist, eine statische Elementfunktion über einen Nullzeiger aufzurufen:

  

p->f() wird nach 5.2.5 [expr.ref] als (*p).f() umgeschrieben. *p ist kein Fehler, wenn p null ist, es sei denn, Lvalue wird in einen rvalue

konvertiert

Allerdings ist diese Entschließung in der Tat falsch.

Es setzt das Konzept eines "leeren lvalue" voraus, das Teil der vorgeschlagenen Auflösung für einen anderen Defekt ist, CWG-Fehler 232 , der die allgemeinere Frage stellt:" Ist die Indirektion durch einen Nullzeiger undefiniertes Verhalten? "

Die Auflösung dieses Fehlers würde bestimmte Formen der Indirektion durch einen Null-Zeiger (wie das Aufrufen einer statischen Elementfunktion) gültig machen. Dieser Fehler ist jedoch noch offen und seine Auflösung wurde nicht in den C ++ Standard übernommen. Bis dieser Fehler geschlossen ist und seine Auflösung in den C ++ - Standard integriert ist, führt die Indirektion über einen Null-Zeiger (oder Dereferenzierung eines Null-Zeigers, wenn man diesen Begriff bevorzugt) immer zu undefiniertem Verhalten.

    
James McNellis 09.03.2011, 16:57
quelle
3

Bezieht sich auf p- & gt; a, wobei p ein Nullzeiger und ein statisches Datenglied ist: §9.4 / 2 sagt "Ein statisches Element kann mit dem Klassenmitglied bezeichnet werden Zugriffssyntax, in diesem Fall wird der Objektausdruck ausgewertet. " "object-expression" ist der Ausdruck links von der. oder die - & gt;.)

    
James Kanze 09.03.2011 18:53
quelle
0

Wenn Sie von der Computer-Seite auf OOP schauen, ist dies eine weitere Möglichkeit zu berechnen, wo sich Daten im Speicher befinden. Wenn Daten nicht statisch sind - sie werden aus dem Instanzzeiger berechnet, wenn Daten statisch sind, werden sie immer als feste Zeiger im Datensegment berechnet. Vorlage fügt nichts hinzu, da zur Kompilierzeit aufgelöst.

Es ist also eine sehr beliebte Technik, NULL als Start-Zeiger zu verwenden (zum Beispiel den Offset des Feldes in der Klasse zu persistieren)

Der obige Code ist korrekt für statische Daten.

    
Dewfy 09.03.2011 16:36
quelle

Tags und Links