Accordint на этот довольно высоко голословный ответ, канонический способ перебора множества, стирающего некоторые элементы, заключается в следующем:
for (it = mySet.begin(); it != mySet.end(); ) {
if (conditionToDelete(*it)) {
mySet.erase(it++);
}
else {
++it;
}
}
Это, конечно же, результат того, что в C ++ 03 не удаляется итератор. В противном случае можно написать it = mySet.erase(it);
Также очевидно, что можно написать
itToDelete = it++;
mySet.erase(itToDelete);
Этот вопрос не о том, как удалять элементы во время итерации. Вопрос в том, почему следующая строка, по-видимому, не привести к неопределенному поведению.
mySet.erase(it++);
Сначала я был уверен, что это должен быть UB, потому что я неправильно думал о постинкременте. Это распространенный (но неправильный) способ думать, что преинкремент произошел ДО остальной части оценки, а постинкремент произошел ПОСЛЕ. Конечно, это неправильно. И постинкремент, и преинкремент имеют побочный эффект увеличения переменной. Разница заключается в значении этих выражений.
Тем не менее, насколько я помню, стандарт C ++ (по крайней мере, C ++ 03) точно не определяет, когда будет иметь место побочный эффект постинкремента. Итак, если у нас нет гарантии, что если аргумент функции, который является выражением postincrement, будет иметь свои побочные эффекты на месте до вход в тело функции, разве это не должно быть UB? Что именно (в соответствии со стандартами), если вообще что-либо, запрещает побочный эффект этого ++, возникающий после того, как итератор был признан недействительным внутри тела функции?
Цитаты из стандарта будут очень приветствоваться.
Ради аргумента давайте также предположим, что итератор множества является встроенным типом, и это на самом деле оператор ++, а не перегруженная оператор-функция.
Это не неопределенное поведение в C ++ 03 потому что есть точка последовательности после того, как все аргументы функции оценены.
Проект стандарта, наиболее близкий к C ++ 03 и общедоступный, N1804, до сих пор нет общедоступной версии проекта стандарта, которую я могу найти, но Статья в Википедии о точках последовательности используемый С ++ 98 а также C ++ 03 как ссылки и фразы соответствуют пунктам ниже N1804.
В разделе 1.9
Выполнение программы параграф 16 говорит (Акцент шахты идет вперед):
При вызове функции (независимо от того, является ли функция встроенной), после оценки всех аргументов функции есть точка последовательности (если есть), который происходит перед выполнением каких-либо выражений или операторов в теле функции. […]
а позже в разделе 5.2.2
Вызов функции параграф 8 говорит:
Порядок оценки аргументов не уточняется. Все побочные эффекты при оценке выражений аргументов вступают в силу до ввода функции. Порядок вычисления выражения postfix и списка выражений аргументов не определен.
Других решений пока нет …