Im C ++ 14-Standard (n3797) lautet der Abschnitt für lvalue to rvalue-Konvertierungen wie folgt (Hervorhebung von mir):
4.1 Lvalue-to-rvalue-Konvertierung [conv.lval]
Ein glvalue (3.10) eines Nicht-Funktions-Array-Typs
T
kann in einen prvalue konvertiert werden. WennT
ein unvollständiger Typ ist, wird ein Programm, das diese Konvertierung erfordert, schlecht gebildet. WennT
ein Nicht-Klassentyp ist, ist der Typ des Prvalue die cv-unqualifizierte Version vonT
. Ansonsten ist der Typ des prvalueT
.Wenn eine Lvalue-to-rvalue-Konvertierung in einem nicht evaluierten Operanden auftritt oder ein Unterausdruck davon (Klausel 5) der in der auf das referenzierte Objekt wird nicht zugegriffen. In allen anderen Fällen ist das Ergebnis der Die Konvertierung wird gemäß den folgenden Regeln festgelegt:
- Wenn
T
eine (möglicherweise cv-qualifizierte)std::nullptr_t
ist, dann ist das Ergebnis eine Null-Zeiger-Konstante.- Andernfalls, wenn
T
über einen Klassentyp verfügt, initialisiert die Konvertierungskopie ein temporäres vom TypT
aus dem glvalue und das Ergebnis der Konvertierung ist ein prvalue für das temporäre.- Andernfalls, wenn das Objekt, auf das der glvalue verweist, einen ungültigen Zeigerwert enthält, ist das Verhalten implementierungsdefiniert.
- Andernfalls, wenn
T
ein (möglicherweise cv-qualifizierter) unsignierter Zeichentyp ist und das Objekt, auf das der glvalue verweist, einen unbestimmten Wert enthält und dieses Objekt keine automatische Speicherdauer hat oder der glvalue war der Operand eines unären&
-Operators oder er war an eine Referenz gebunden, das Ergebnis ist ein unspezifizierter Wert.- Andernfalls, wenn das Objekt, auf das sich der glvalue bezieht, einen unbestimmten Wert hat, ist das Verhalten nicht definiert.
- Andernfalls ist das vom glvalue angegebene Objekt das Prvalue-Ergebnis.
- [ Hinweis: Siehe auch 3.10]
Was ist die Bedeutung dieses Absatzes (in Fettdruck)?
Wenn dieser Absatz nicht hier wäre, würden die Situationen, in denen er angewendet wird, zu undefiniertem Verhalten führen. Normalerweise würde ich erwarten, dass der Zugriff auf einen unsigned char
-Wert, während er einen unbestimmten Wert hat, zu undefiniertem Verhalten führt. Aber mit diesem Absatz bedeutet das,
&
weiter oder verbinde ihn mit einer Referenz oder unsigned char
keine automatische Speicherdauer hat, dann ergibt die Umwandlung einen unspezifizierten Wert und kein undefiniertes Verhalten.
Bin ich richtig zu dem Schluss, dass dieses Programm:
%Vor% ist vom Standard gut definiert und muss eine Sequenz von 500 nicht spezifizierten Ints ausgeben, während das gleiche Programm, in dem T = int
, ein undefiniertes Verhalten hat?
IIUC, einer der Gründe, um es UB zu machen, Dinge mit unbestimmten Werten zu lesen, besteht darin, eine aggressive totale Speichereliminierung durch den Optimierer zuzulassen. Dieser Absatz kann also bedeuten, dass ein kompilierender Compiler nicht so viel Optimierung durchführen kann, wenn er mit unsigned char
oder Arrays von unsigned char
arbeitet.
Wenn ich richtig verstehe, was ist der Grund für diese Regel? Wann ist es nützlich, unsigned char
lesen zu können, die unbestimmte Werte haben und nicht spezifizierte Ergebnisse anstelle von UB erhalten? Ich habe das Gefühl, dass, wenn sie sich so viel Mühe geben, diesen Teil der Regel zu erstellen, sie motiviert waren, bestimmten Codebeispielen zu helfen, die ihnen wichtig waren, oder mit einem anderen Teil des Standards konsistent zu sein oder ein anderes Problem zu vereinfachen . Aber ich habe keine Ahnung, was das sein könnte.
In vielen Situationen wird Code einige Teile eines PODS oder Arrays schreiben, ohne alles zu schreiben, und dann Funktionen wie memcpy
oder fwrite
verwenden, um das gesamte Ding zu kopieren oder zu schreiben, ohne Rücksicht darauf, welche Teile Werte zugewiesen hatten und welche nicht. Obwohl es für C ++ - Code nicht sehr üblich ist, bytebasierte Operationen zu verwenden, um den Inhalt von Aggregaten zu kopieren oder zu schreiben, ist die Fähigkeit, dies zu tun, ein grundlegender Teil der Sprache. Die Forderung, dass ein Programm bestimmte Werte in alle Teile eines Objekts schreibt, einschließlich derjenigen, für die sich niemals etwas "interessieren" wird, würde die Effizienz unnötig beeinträchtigen.
Tags und Links c++ undefined-behavior language-lawyer c++14 lvalue-to-rvalue