Первое - неопределенное поведение. Не указано, оценивается ли list[i]
(для предоставления lvalue для lhs присвоения) до или после вызова функции objects.at
.
Следовательно, существует законный порядок различных частей выражения, в котором к i
обращаются (в list[i]
) и изменяют отдельно (в i++
) без промежуточной точки последовательности.
Это как раз условие неопределенного поведения в стандарте C ++ - существует ли такой законный порядок. Стандарт IIRC C выражает это немного по-другому, но с тем же эффектом.
Если сомневаетесь, не пишите выражение, которое использует оператор приращения, а также использует то же значение в любом другом месте выражения. Вы можете сделать это с помощью оператора запятой (i++, i++
хорошо) и условного оператора (i ? i++ : i--
хорошо), потому что в них есть точки последовательности, но это редко стоит. ||
и &&
также, и что-то вроде p != end_p && *(p++) = something;
не совсем неправдоподобно. Любое другое использование, и если вы смотрите на него достаточно долго, вы обычно можете выработать порядок оценки, который все испортит.
Это кроме понимания сложных for
выражений и for
циклов с пустыми телами.