[basic.scope.pdecl] / 1 des C ++ 20-Standardentwurfs enthielt das folgende (nicht normative) Beispiel in einer Notiz (Teilzitat vor dem Zusammenführen der Pull-Anforderung 3580 , siehe Antwort auf diese Frage):
unsigned char x = x;
[...] x wird mit einem eigenen (unbestimmten) Wert initialisiert.
Hat dies tatsächlich ein genau definiertes Verhalten in C ++ 20?
Im Allgemeinen hat die Selbstinitialisierung des Formulars T x = x;
ein undefiniertes Verhalten, da der x
Wert vor Abschluss der Initialisierung unbestimmt ist. Das Auswerten unbestimmter Werte führt im Allgemeinen zu undefiniertem Verhalten ( [basic.indent] / 2 ). In [basic.indent] /2.3 gibt es jedoch eine spezielle Ausnahme , die das direkte Initialisieren einer unsigned char
Variablen aus einem l- unsigned char
Wert mit unbestimmtem Wert ermöglicht (was das Initialisieren mit einem unbestimmten Wert verursacht) ).
Dies allein verursacht daher kein undefiniertes Verhalten, sondern würde für andere Typen T
, die keine vorzeichenlosen engen Zeichentypen sind, oder std::byte
z int x = x;
. Diese Überlegungen wurden auch in C ++ 17 und früher angewendet, siehe auch verknüpfte Fragen unten.
Selbst für unsigned char x = x;
den aktuellen Entwurf [basic.lifetime] / 7 heißt es jedoch:
In ähnlicher Weise ist die Verwendung der Eigenschaften des Gl-Werts, die nicht von seinem Wert abhängen, genau definiert, bevor die Lebensdauer eines Objekts [...] begonnen hat. Das Programm hat ein undefiniertes Verhalten, wenn:
Der gl-Wert wird verwendet, um auf das Objekt zuzugreifen, oder
[...]
Dies scheint zu implizieren, dass x
der Wert im Beispiel nur während seiner Lebensdauer verwendet werden kann.
[basic.lifetime] / 1 sagt:
[...]
Die Lebensdauer eines Objekts vom Typ T beginnt, wenn:
- [...] und
- seine Initialisierung (falls vorhanden) ist abgeschlossen (einschließlich leerer Initialisierung) ([dcl.init]),
[...]
Somit x
beginnt die Lebensdauer erst, nachdem die Initialisierung abgeschlossen ist. Im angegebenen Beispiel wird x
der Wert jedoch verwendet, bevor x
die Initialisierung abgeschlossen ist. Daher hat die Verwendung undefiniertes Verhalten.
Ist meine Analyse korrekt und wenn ja, hat sie Auswirkungen auf ähnliche Fälle der Verwendung vor der Initialisierung wie z
int x = (x = 1);
Welche waren, soweit ich das beurteilen kann, auch in C ++ 17 und früher gut definiert?
Beachten Sie, dass in C ++ 17 (endgültiger Entwurf) die zweite Voraussetzung für den Beginn der Lebensdauer anders war :
- Wenn das Objekt eine nicht leere Initialisierung hat, ist seine Initialisierung abgeschlossen.
Da x
die Initialisierung nach der Definition von C ++ 17 (aber nicht nach der Definition im aktuellen Entwurf) leer wäre, hätte ihre Lebensdauer bereits begonnen, wenn im Initialisierer in den oben angegebenen Beispielen darauf zugegriffen wird, und daher gab es in beiden Beispielen kein undefiniertes Verhalten aufgrund der Lebensdauer von x
in C ++ 17.
Der Wortlaut vor C ++ 17 ist wieder anders, aber mit dem gleichen Ergebnis.
Bei der Frage geht es nicht um undefiniertes Verhalten bei Verwendung unbestimmter Werte, das z. B. in folgenden Fragen behandelt wurde:
int x ^= x;
ist syntaktisch nicht wohlgeformt. Sie können entweder eine Variablendefinition mit dem Initialisierer (dh int x = x;
obwohl es sich um UB handelt) oder eine xor-Zuweisungsausdrucksanweisung (dh x ^= x;
obwohl es sich um UB x
handelt , wenn es sich um einen Typ handelt int
, die standardmäßig initialisiert und nicht zuvor zugewiesen wurde) haben. Sie können diese beiden nicht zu einem mischen.