Accordint к этому довольно высокому ответу, канонический способ итерации через набор, стирающий некоторые элементы, таков:
for (it = mySet.begin(); it != mySet.end(); ) {
if (conditionToDelete(*it)) {
mySet.erase(it++);
}
else {
++it;
}
}
Это, конечно, результат С++ 03 set erase, не возвращающий итератор. В противном случае можно было бы написать it = mySet.erase(it);
. Очевидно также, что можно написать
itToDelete = it++;
mySet.erase(itToDelete);
Этот вопрос не о том, как удалять элементы во время итерации. Вопрос в том, почему следующая строка, по-видимому, не приводит к поведению undefined.
mySet.erase(it++);
Сначала я был уверен, что это должен быть UB, потому что я неправильно думал о постинкрете. Это общий (но неправильный) способ думать о предварительном приращении, как это происходит перед остальной оценкой, и постинкрестностью, происходящей ПОСЛЕ. Конечно, это неправильно. Оба постинкремента и preincrement имеют побочный эффект приращения переменной. Разница заключается в значении этих выражений.
Тем не менее, насколько я помню, стандарт С++ (по крайней мере, С++ 03) не уточняет, когда произойдет побочный эффект постинкремента. Итак, если у нас нет гарантии, что если аргумент функции, являющийся выражением постинкремента, будет иметь свои побочные эффекты на месте перед входом в тело функции, разве это не должно быть UB? Что именно (по стандартам), если что-либо, запрещает его побочный эффект ++, происходящий после того, как итератор был недействителен внутри тела функции?
Цитаты из стандарта были бы очень желанными.
Для аргументации давайте предположим, что set iterator - это встроенный тип, и это фактически оператор ++, а не перегруженная оператор-функция