Почему поведение mySet.erase(it ++) undefined не так ли? - программирование
Подтвердить что ты не робот

Почему поведение mySet.erase(it ++) undefined не так ли?

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 - это встроенный тип, и это фактически оператор ++, а не перегруженная оператор-функция

4b9b3361

Ответ 1

Это не undefined поведение в С++ 03, потому что после всех аргументов функции есть точка последовательности.

Проект стандарта, который ближе всего к С++ 03 и который общедоступен, N1804, нет общедоступной версии черновик стандарта, который я могу найти, но статья Википедии о точках последовательности использовал С++ 98 и С++ 03 в качестве ссылок, а фразы в соответствии с нижеследующими параграфами от N1804.

В разделе 1.9 В пункте 16 выполнения программы говорится (акцент мой на будущее):

При вызове функции (независимо от того, является ли функция встроенной), появляется точка последовательности после оценки всех аргументов функции (если таковая имеется), которая выполняется перед выполнением любых выражений или операторов в теле функции. [...]

а затем в разделе 5.2.2 В пункте 8 функционального вызова говорится:

Порядок оценки аргументов неуточнен. Все побочные эффекты оценок выражения аргументов вступают в силу до ввода функции. Порядок оценки постфиксного выражения и списка выражений аргумента не указан.