この非常に支持された回答によると、いくつかの要素を消去するセットを反復処理する標準的な方法は次のとおりです。
for (it = mySet.begin(); it != mySet.end(); ) {
if (conditionToDelete(*it)) {
mySet.erase(it++);
}
else {
++it;
}
}
もちろん、これは C++03 の set erase が反復子を返さない結果です。それ以外の場合は、次のように書くit = mySet.erase(it);
ことができます。
itToDelete = it++;
mySet.erase(itToDelete);
この質問は、反復中に要素を削除する方法に関するものではありません。問題は、次の行が明らかに未定義の動作にならない理由です。
mySet.erase(it++);
最初は、ポストインクリメントについて間違った考えを持っていたので、これは UB でなければならないと確信していました。プレインクリメントが残りの評価の前に発生し、ポストインクリメントが後に発生すると考えるのは一般的な (しかし間違った) 方法です。もちろん、これは間違っています。ポストインクリメントとプリインクリメントの両方に、変数をインクリメントするという副作用があります。違いは、それらの式の値です。
とはいえ、私が覚えている限り、C++ 標準 (少なくとも C++03) では、ポストインクリメントの副作用がいつ発生するかを正確に指定していません。では、ポストインクリメント式である関数の引数が関数本体に入る前に副作用を持っているという保証がない限り、これはUB ではないでしょうか? 関数本体内でイテレータが無効化された後に発生する it++ の副作用を禁止しているのは、正確には (標準的に) 何でしょうか?
標準からの引用は大歓迎です。
議論のために、セットの反復子が組み込み型であり、これが実際には演算子 ++ であり、オーバーロードされた演算子関数ではないとします。