Ich werde nur eine detaillierte Referenz für die Als-ob- Regel und das flüchtige Schlüsselwort hinzufügen . (Folgen Sie am Ende dieser Seiten den Anweisungen "Siehe auch" und "Verweise", um zu den ursprünglichen Spezifikationen zurückzukehren. Cppreference.com ist jedoch viel einfacher zu lesen / zu verstehen.)
Insbesondere möchte ich, dass Sie diesen Abschnitt lesen
flüchtiges Objekt - ein Objekt, dessen Typ flüchtig qualifiziert ist, oder ein Unterobjekt eines flüchtigen Objekts oder ein veränderliches Unterobjekt eines const-flüchtigen Objekts. Jeder Zugriff (Lese- oder Schreibvorgang, Elementfunktionsaufruf usw.), der über einen glvalue-Ausdruck vom Typ flüchtig qualifiziert erfolgt, wird zum Zwecke der Optimierung als sichtbarer Nebeneffekt behandelt (dh innerhalb eines einzelnen Ausführungsthreads flüchtig) Zugriffe können nicht mit einem anderen sichtbaren Nebeneffekt optimiert oder neu angeordnet werden, der vor oder nach dem flüchtigen Zugriff sequenziert wird. Dadurch eignen sich flüchtige Objekte für die Kommunikation mit einem Signalhandler, jedoch nicht mit einem anderen Ausführungsthread, siehe std :: memory_order ). Jeder Versuch, über einen nichtflüchtigen Gl-Wert (z. B. durch eine Referenz oder einen Zeiger auf einen nichtflüchtigen Typ) auf ein flüchtiges Objekt zu verweisen, führt zu undefiniertem Verhalten.
Also das flüchtige Schlüsselwort speziell darum, die Compileroptimierung für glvalues zu deaktivieren . Das einzige, was das flüchtige Schlüsselwort hier beeinflussen kann, ist möglicherweise return x
, dass der Compiler mit dem Rest der Funktion machen kann, was er will.
Inwieweit der Compiler die Rückgabe optimieren kann, hängt davon ab, inwieweit der Compiler in diesem Fall den Zugriff von x optimieren darf (da er nichts neu anordnet und streng genommen den Rückgabeausdruck nicht entfernt. Es gibt den Zugriff , aber es liest und schreibt in den Stapel, der rationalisiert werden sollte.) Wenn ich es also lese, ist dies eine Grauzone, in der der Compiler optimieren darf, und kann leicht in beide Richtungen argumentiert werden.
Randnotiz: In diesen Fällen wird immer davon ausgegangen, dass der Compiler das Gegenteil von dem tut, was Sie wollten / brauchten. Sie sollten entweder die Optimierung deaktivieren (zumindest für dieses Modul) oder versuchen, ein definierteres Verhalten für das zu finden, was Sie möchten. (Dies ist auch der Grund, warum Unit-Tests so wichtig sind.) Wenn Sie glauben, dass es sich um einen Fehler handelt, sollten Sie ihn mit den Entwicklern von C ++ besprechen.
Das alles ist immer noch sehr schwer zu lesen. Versuchen Sie also, das einzubeziehen, was ich für relevant halte, damit Sie es selbst lesen können.
glvalue Ein glvalue-Ausdruck ist entweder lvalue oder xvalue.
Eigenschaften:
Ein gl-Wert kann implizit in einen pr-Wert mit impliziter Konvertierung von lWert zu rWert, Array zu Zeiger oder Funktion zu Zeiger konvertiert werden. Ein Gl-Wert kann polymorph sein: Der dynamische Typ des Objekts, das er identifiziert, ist nicht unbedingt der statische Typ des Ausdrucks. Ein gl-Wert kann einen unvollständigen Typ haben, sofern der Ausdruck dies zulässt.
xvalue Die folgenden Ausdrücke sind xvalue-Ausdrücke:
ein Funktionsaufruf oder ein überladener Operatorausdruck, dessen Rückgabetyp eine Wertreferenz auf ein Objekt ist, wie z. B. std :: move (x); a [n], der eingebaute tiefgestellte Ausdruck, wobei ein Operand ein Array-Wert ist; am, das Mitglied des Objektausdrucks, wobei a ein r-Wert und m ein nicht statisches Datenelement vom Nichtreferenztyp ist; a. * mp, der Zeiger auf das Element des Objektausdrucks, wobei a ein r-Wert und mp ein Zeiger auf das Datenelement ist; ein ? b: c, der ternäre bedingte Ausdruck für einige b und c (Einzelheiten siehe Definition); ein Cast-Ausdruck, um den Verweis auf den Objekttyp zu bewerten, z. B. static_cast (x); Jeder Ausdruck, der nach temporärer Materialisierung ein temporäres Objekt bezeichnet. (seit C ++ 17) Eigenschaften:
Gleich wie rWert (unten). Gleich wie glvalue (unten). Insbesondere binden xvalues wie alle rvalues an rvalue-Referenzen, und wie alle glvalues können xvalues polymorph sein und xvalues, die keine Klasse sind, können cv-qualifiziert sein.
lWert Die folgenden Ausdrücke sind lWert-Ausdrücke:
Der Name einer Variablen, einer Funktion oder eines Datenelements, unabhängig vom Typ, z. B. std :: cin oder std :: endl. Selbst wenn der Variablentyp eine rWertreferenz ist, ist der Ausdruck, der aus seinem Namen besteht, ein lWertausdruck. ein Funktionsaufruf oder ein überladener Operatorausdruck, dessen Rückgabetyp eine Wertreferenz ist, wie z. B. std :: getline (std :: cin, str), std :: cout << 1, str1 = str2 oder ++ it; a = b, a + = b, a% = b und alle anderen integrierten Ausweisungs- und zusammengesetzten Zuweisungsausdrücke; ++ a und --a, die integrierten Vorinkrementierungs- und Vordekrementierungsausdrücke; * p, der eingebaute Indirektionsausdruck; a [n] und p [n], die integrierten tiefgestellten Ausdrücke, außer wenn a ein Array-Wert ist (seit C ++ 11); am, das Mitglied des Objektausdrucks, außer wenn m ein Elementaufzähler oder eine nicht statische Elementfunktion ist, oder wobei a ein r-Wert ist und m ein nicht statisches Datenelement vom Nichtreferenztyp ist; p-> m, das eingebaute Element des Zeigerausdrucks, außer wenn m ein Elementaufzähler oder eine nicht statische Elementfunktion ist; a. * mp, der Zeiger auf das Element des Objektausdrucks, wobei a ein Wert und mp ein Zeiger auf das Datenelement ist; p -> * mp, der eingebaute Zeiger auf das Element des Zeigerausdrucks, wobei mp ein Zeiger auf das Datenelement ist; a, b, der eingebaute Kommaausdruck, wobei b ein Wert ist; ein ? b: c, der ternäre bedingte Ausdruck für einige b und c (z. B. wenn beide Werte desselben Typs sind, aber Einzelheiten siehe Definition); ein String-Literal wie "Hallo Welt!"; ein Cast-Ausdruck für den Referenztyp lvalue, z. B. static_cast (x); ein Funktionsaufruf oder ein überladener Operatorausdruck, dessen Rückgabetyp ist rWertreferenz auf Funktion; Ein Cast-Ausdruck, der auf den Funktionstyp verweist, z. B. static_cast (x). (seit C ++ 11) Eigenschaften:
Gleich wie glvalue (unten). Die Adresse eines l-Werts kann verwendet werden: & ++ i 1
und & std :: endl sind gültige Ausdrücke. Ein modifizierbarer Wert kann als linker Operand der integrierten Zuweisungs- und zusammengesetzten Zuweisungsoperatoren verwendet werden. Ein l-Wert kann verwendet werden, um eine l-Wert-Referenz zu initialisieren; Dadurch wird dem durch den Ausdruck identifizierten Objekt ein neuer Name zugeordnet.
als ob Regel
Der C ++ - Compiler darf alle Änderungen am Programm vornehmen, solange Folgendes zutrifft:
1) An jedem Sequenzpunkt sind die Werte aller flüchtigen Objekte stabil (vorherige Auswertungen sind abgeschlossen, neue Auswertungen werden nicht gestartet) (bis C ++ 11). 1) Zugriffe (Lese- und Schreibvorgänge) auf flüchtige Objekte erfolgen streng gemäß der Semantik der Ausdrücke, in denen sie vorkommen. Insbesondere werden sie in Bezug auf andere flüchtige Zugriffe auf denselben Thread nicht neu angeordnet. (seit C ++ 11) 2) Beim Beenden des Programms sind die in Dateien geschriebenen Daten genau so, als ob das Programm wie geschrieben ausgeführt worden wäre. 3) Aufforderungstext, der an interaktive Geräte gesendet wird, wird angezeigt, bevor das Programm auf die Eingabe wartet. 4) Wenn das ISO C-Pragma #pragma STDC FENV_ACCESS unterstützt und auf ON gesetzt ist,
Wenn Sie die technischen Daten lesen möchten, müssen Sie diese meiner Meinung nach lesen
Verweise
C11-Norm (ISO / IEC 9899: 2011): 6.7.3 Typqualifizierer (S. 121-123)
C99-Norm (ISO / IEC 9899: 1999): 6.7.3 Typqualifizierer (S. 108-110)
Norm C89 / C90 (ISO / IEC 9899: 1990): 3.5.3 Typqualifizierer