2013-10-23 18 views
10

Accordint to this quite highly upvoted answer, il modo canonico per scorrere un insieme cancellazione di alcuni elementi è la seguente:Perché il comportamento non definito mySet.erase (it ++) non è definito o è?

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

Questo, naturalmente, è il risultato di C++ 03 del set di cancellazione non tornare un iteratore. In caso contrario, si potrebbe scrivere it = mySet.erase(it); E 'anche evidente che uno può scrivere

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

Questa domanda non è su come eliminare gli elementi, mentre l'iterazione. La domanda è: perché la seguente riga apparentemente non ha come risultato un comportamento non definito.

mySet.erase(it++); 

All'inizio ero sicuro che questo doveva essere UB, perché pensavo nel modo sbagliato il post. È un modo comune (ma sbagliato) di pensare al pre-incremento come accade PRIMA del resto della valutazione, e il postincremento accade dopo. Certo, questo è sbagliato. Sia il postincremento che il preincremento hanno l'effetto collaterale di incrementare la variabile. La differenza è il valore di quelle espressioni.

Detto questo, per quanto posso ricordare, lo standard C++ (almeno quello C++ 03) non specifica esattamente quando si verificherà l'effetto collaterale del postincremento. Quindi, a meno che non abbiamo una garanzia che se un argomento di funzione che è un'espressione di postincremento avrà i suoi effetti collaterali in vigore prima di inserendo il corpo della funzione, non dovrebbe essere questo UB? Che cosa esattamente (standard-saggio), semmai, vieta l'effetto collaterale di esso ++ dopo che l'iteratore è stato invalidato all'interno del corpo della funzione?

Le citazioni dallo standard sarebbero molto gradite.

Nell'interesse di un argomento Supponiamo anche iteratore quel set è costruito in tipo e questo è in realtà operatore ++, non il sovraccarico operatore funzione

+1

Lo standard non richiede che tutti gli argomenti delle funzioni vengano valutati ** prima ** il flusso di controllo entra nel corpo della funzione chiamata? –

+0

@ H2CO3: la valutazione di qualcosa coinvolge tutti i suoi effetti collaterali? –

+0

Sono abbastanza sicuro che lo faccia, ma sono in procinto di controllare lo standard. –

risposta

11

Questo non è undefined behavior in C++ 03 perché esiste un punto di sequenza dopo che tutti gli argomenti della funzione sono stati valutati.

La bozza di standard che è più vicino al C++ 03 e che è pubblicamente disponibile è N1804, non esiste una versione pubblica del progetto di norma da prima che io possa trovare, ma la Wikipedia article on sequence points utilizzato C++ 98 e C++ 03 come riferimenti e le frasi sono coerenti con i paragrafi seguenti da N1804.

Nella sezione 1.9L'esecuzione del programma paragrafo dice (sottolineatura mia andare avanti):

Quando si chiama una funzione (se la funzione è in linea), v'è una sequenza punto dopo la valutazione di tutti gli argomenti della funzione (se presenti) che si verifica prima dell'esecuzione di qualsiasi espressione o istruzione nel corpo della funzione. [...]

e più tardi nella sezione 5.2.2funzione chiamata paragrafo dice:

L'ordine di valutazione degli argomenti non è specificato. Tutti gli effetti collaterali delle valutazioni delle espressioni degli argomenti hanno effetto prima che la funzione venga immessa. L'ordine di valutazione dell'espressione postfissa e dell'elenco di espressioni dell'argomento non è specificato.