Was aus i = i++ + 1; legal in C++17?
Bevor Sie beginnen zu Schreien Undefiniertes Verhalten, das ist explizit aufgelistet in N4659 (C++17)
i = i++ + 1; //the value of i is incremented
Doch in N3337 (C++11)
i = i++ + 1; //the behavior is undefined
Was geändert?
Von dem, was ich sammeln können, von [N4659 basic.exec]
Außer, wo bemerkt, Auswertungen von Operanden der einzelnen Operatoren und Teilausdrücke der einzelnen Ausdrücke sind nicht sequenzielle. [...] Die Wert-Berechnungen der Operanden eines operators sind sequenziert, bevor der Wert der Berechnung des Ergebnis des operators. Wenn eine Nebenwirkung auf ein Speicher ist nicht sequenzielle relativ zu entweder eine weitere Nebenwirkung, die auf die gleiche Speicherstelle oder ein Wert-Berechnung über den Wert jedes Objekts in die gleiche Erinnerung Lage, und Sie sind nicht potenziell gleichzeitigen, ist das Verhalten undefiniert.
Wo Wert definiert bei [N4659 basic.Typ]
Für trivial kopierbaren Arten, die Wert-Darstellung ist ein Satz von bits im Objekt-Repräsentation bestimmt, dass ein Wertdie einem einzelnen element eine von der Implementierung definierte Gruppe von Werten
Außer, wo bemerkt, Auswertungen von Operanden der einzelnen Operatoren und Teilausdrücke der einzelnen Ausdrücke sind nicht sequenzielle. [...] Die Wert-Berechnungen der Operanden eines operators sind sequenziert, bevor der Wert der Berechnung des Ergebnis des operators. Wenn eine Nebenwirkung auf ein Skalar-Objekt ist nicht sequenzielle relativ zu entweder eine andere Nebenwirkung, auf die gleiche Skalare Objekt oder einen Wert-Berechnung mit dem Wert des gleichen Skalare Objekt, das Verhalten ist undefiniert.
Ebenso Wert definiert bei [N3337 basic.Typ]
Für trivial kopierbaren Arten, die Wert-Darstellung ist ein Satz von bits im Objekt-Repräsentation bestimmt, dass ein Wertdie einem einzelnen element eine von der Implementierung definierte Gruppe von Werten.
Sind Sie identisch, außer die Erwähnung der Gleichzeitigkeit, die nicht der Materie, und mit der Verwendung von Speicher statt scalar Objektwo
Arithmetische Typen, Aufzählungstypen, Zeiger-Typen, Zeiger auf member-Typen, die
std::nullptr_t
- und cv-qualifizierte Versionen dieser Typen werden zusammenfassend als Skalare Typen.
Die nicht auf das Beispiel.
Vom [N4659 expr.ass]
Dem Zuweisungsoperator (=) und dem zusammengesetzten Zuweisungsoperatoren alle in der Gruppe von rechts nach Links. Alle benötigen eine modifiable lvalue als Ihre linken Operanden und gibt nur ein lvalue bezogen auf die linke operand. Das Ergebnis ist in allen Fällen ein bit-Feld, wenn der linke operand ein bit-Feld. In allen Fällen der Abtretung ist sequenziert, die nach dem Wert-Berechnung des rechten und des linken Operanden, und bevor der Wert die Berechnung der Zuweisung Ausdruck. Der Rechte operand ist sequenziert, bevor der linke operand.
Vom [N3337 expr.ass]
Dem Zuweisungsoperator (=) und dem zusammengesetzten Zuweisungsoperatoren alle in der Gruppe von rechts nach Links. Alle benötigen eine modifiable lvalue als Ihre linken Operanden und gibt nur ein lvalue bezogen auf die linke operand. Das Ergebnis ist in allen Fällen ein bit-Feld, wenn der linke operand ein bit-Feld. In allen Fällen der Abtretung ist sequenziert, die nach dem Wert-Berechnung des rechten und des linken Operanden, und bevor der Wert die Berechnung der Zuweisung Ausdruck.
Nur mit dem Unterschied, dass der Letzte Satz fehlen in N3337.
Den letzten Satz allerdings, sollte keine Bedeutung, da der linke operand i
ist weder "ein weiterer Nebeneffekt" noch "mit dem Wert des gleichen skalaren Objekt" als id-expression ist ein lvalue.
InformationsquelleAutor der Frage Passer By | 2017-12-07
Du musst angemeldet sein, um einen Kommentar abzugeben.
In C++11-der Akt der "Abtretung", d.h. die Nebenwirkung der änderung der LHS, sequenziert nach den Wert Berechnung des rechten Operanden. Beachten Sie, dass dies eine relativ "schwache" Gewährleistung: es produziert Sequenzierung nur mit Bezug auf Wert Berechnung der RHS. Es sagt nichts über die Nebenwirkungendie vorhanden sein könnten, die in die RS, und da das auftreten von Nebenwirkungen ist nicht Teil der Wert Berechnung. Die Anforderungen von C++11 zu etablieren keine relativen Sequenzierung zwischen dem Akt der Zuordnung und Nebenwirkungen von RS. Dies ist, was schafft das Potenzial für UB.
Die einzige Hoffnung in diesem Fall ist keine zusätzliche Garantien von bestimmten Operatoren im RHS. Wenn die RHS verwendet ein Präfix
++
Sequenzierung der spezifischen Eigenschaften der Präfix-form++
hätte den Tag gerettet in diesem Beispiel. Aber postfix++
ist eine andere Geschichte: Sie macht nicht solche Garantien. In C++11, die Nebenwirkungen der=
- und postfix -++
am Ende nicht sequenzielle zueinander in diesem Beispiel. Und das ist UB.In C++17 einen zusätzlichen Satz ergänzt um die Angabe des zuweisungsoperators:
In Kombination mit den oben genannten macht es für eine sehr starke Garantie. Es Sequenzen alles das passiert in der RHS (einschließlich Nebenwirkungen) vor alles das passiert in der LS. Da die eigentliche Zuweisung sequenziert nach LHS (und RS), die extra-Sequenzierung völlig isoliert den Akt der Zuordnung aus irgendwelchen Nebenwirkungen vorhanden in RS. Diese stärkere Sequenzierung ist es, was beseitigt die oben genannten UB.
(Aktualisiert berücksichtigen @John Bollinger ' s Kommentare.)
InformationsquelleAutor der Antwort AnT
Identifiziert dich der neue Satz
und Sie richtig erkannt, dass die Auswertung des linken Operanden als ein lvalue ist irrelevant. Allerdings sequenziert, bevor angegeben ist eine transitive relation. Die komplette Rechte operand (einschließlich der post-Inkrement) ist daher auch sequenziert, bevor Sie die Zuordnung. In C++11, nur die Wert Berechnung des rechten Operanden wurde sequenziert, bevor Sie die Zuordnung.
InformationsquelleAutor der Antwort
In älteren C++ - standards und in C11, die definition des zuweisungsoperators text endet mit dem text:
Bedeutung, dass Nebenwirkungen, die in die Operanden sind nicht sequenzielle und daher auf jeden Fall zu undefiniertem Verhalten, wenn Sie die gleiche variable verwenden.
Dieser text war einfach entfernt, C++11, wobei es etwas unklar. Ist es UB oder ist es nicht? Dieser Klärung in C++17, wo Sie Hinzugefügt:
Als eine Randnotiz, in der auch ältere standards, all das wurde sehr deutlich gemacht, Beispiel aus C99:
Grundsätzlich in C11/C++11, ist Sie Durcheinander, wenn Sie entfernt, dieser text.
InformationsquelleAutor der Antwort Lundin