2013-10-23 21 views
10

accordint to this quite highly upvoted answer, die kanonische Weise durch einen Satz zu wiederholen, einige Elemente zu löschen ist die folgende:Warum ist mySet.Erase (it ++) nicht definiert, oder?

for (it = mySet.begin(); it != mySet.end();) { 
    if (conditionToDelete(*it)) { 
     mySet.erase(it++); 
    } 
    else { 
     ++it; 
    } 
} 

Dies ist natürlich ein Ergebnis von C++ 03 des Satzes Lösch nicht einen Iterator zurück. Sonst könnte man schreiben it = mySet.erase(it); Es ist auch offensichtlich, dass man

itToDelete = it++; 
mySet.erase(itToDelete); 

Diese Frage schreiben kann, ist nicht etwa, wie Elemente, während das Iterieren zu löschen. Die Frage ist, warum die folgende Zeile scheinbar nicht zu undefiniertem Verhalten führt.

mySet.erase(it++); 

Zuerst war ich sicher, dass dies UB sein musste, weil ich in die falsche Art und Weise über Postinkrement denken. Es ist eine übliche (aber falsche) Art zu denken, dass Vor-Inkrementieren als VOR der Ruhe der Evaluierung geschieht und Post-Inkrementieren NACHFOLGEND geschieht. Natürlich ist das falsch. Postinkrement und Präinkrement haben den Nebeneffekt, die Variable zu inkrementieren. Der Unterschied ist der Wert dieser Ausdrücke.

Das gesagt, so weit ich mich erinnern kann, spezifiziert der C++ - Standard (zumindest der C++ 03) nicht genau, wann die Nebenwirkung der Postinkrementierung stattfinden wird. Also, es sei denn, wir haben eine Garantie, dass, wenn ein Funktionsargument, das ein postincrement-Ausdruck ist, seine vor in den Funktionskörper eingeben, sollte dies nicht UB sein? Was verbietet (standardgemäß), wenn überhaupt, die Nebenwirkung von it ++, nachdem der Iterator innerhalb des Funktionskörpers ungültig gemacht wurde?

Zitate aus dem Standard wäre sehr willkommen.

Für einen umfassenden willen Argument wollen wir auch, dass Set annehmen Iterator in Art einer eingebauten und das ist eigentlich Operator ++, nicht die überladenen Operator-Funktion

+1

Erfordert der Standard nicht, dass alle Funktionsargumente ausgewertet werden ** bevor ** der Kontrollfluss in den Körper der aufgerufenen Funktion eintritt? –

+0

@ H2CO3: Bezieht die Bewertung etwas mit all seinen Nebenwirkungen ein? –

+0

Ich bin mir ziemlich sicher, dass es das tut, aber ich bin dabei, den Standard zu überprüfen. –

Antwort

11

Diese nicht undefined behavior in C++ 03 weil es einen Sequenzpunkt gibt, nachdem alle Funktionsargumente ausgewertet worden sind.

Der Norm-Entwurf, der am nächsten zu C++ 03 ist, und das ist öffentlich N1804 zur Verfügung steht, da der Standard-Entwurf keine öffentliche Version von davor ist, ich aber die Wikipedia article on sequence points verwendet C++ 98 und finden C++ 03 als Referenzen und die Sätze stimmen mit den folgenden Abschnitten aus N1804 überein.

In Abschnitt 1.9Programmausführung Absatz sagt (Schwerpunkt Mine vorwärts gehen):

Wenn eine Funktion aufgerufen wird (ob die Funktion inline ist), gibt es eine Folge Punkt nach der Auswertung aller Funktionsargumente (falls vorhanden), die vor der Ausführung von Ausdrücken oder Anweisungen im Funktionskörper stattfinden. [...]

und später in Abschnitt 5.2.2Funktionsaufruf Absatz sagt:

Die Reihenfolge der Auswertung der Argumente ist nicht spezifiziert. Alle Nebeneffekte der Argumentauswertung werden wirksam, bevor die Funktion eingegeben wird. Die Reihenfolge der Auswertung des Postfix-Ausdrucks und der Argumentliste ist nicht spezifiziert.