Собственные операторные выражения не эквивалентны перегруженным операторным выражениям.Существует точка последовательности при привязке значений к аргументам функции, что делает версии operator++()
четко определенными.Но это не существует для случая нативного типа.
Во всех четырех случаях i
изменяется дважды в пределах полного выражения.Поскольку ,
, ||
или &&
не отображаются в выражениях, это мгновенное значение UB.
§5 / 4:
Между предыдущей и следующей точкой последовательностискалярный объект должен иметь свое сохраненное значение, измененное не более одного раза путем вычисления выражения.
Правка для C ++ 0x (обновлено)
§1.9 / 15:
Вычисления значений операндов оператора секвенируются до вычисления значения результата оператора.Если побочный эффект на скалярный объект не секвенирован относительно другого побочного эффекта на тот же скалярный объект или вычисления значения с использованием значения того же скалярного объекта, поведение не определено.
Обратите внимание, однакочто вычисление значения и побочный эффект - это две разные вещи.Если ++i
эквивалентно i = i+1
, тогда +
является вычислением значения, а =
является побочным эффектом.Начиная с 1.9 / 12:
Оценка выражения (или подвыражения) в целом включает в себя оба вычисления значения (включая определение идентификатора объекта для оценки glvalue и выборку значения, ранее назначенного дляобъект для предварительной оценки) и инициирование побочных эффектов.
Таким образом, хотя вычисления значений более строго упорядочены в C ++ 0x, чем в C ++ 03, побочные эффекты отсутствуют. Два побочных эффекта в одном и том же выражении, если не указано иное, приводят к UB.
Вычисления значений в любом случае упорядочены по их зависимостям данных, и, если побочные эффекты отсутствуют, их порядок оценки не наблюдается, поэтомуЯ не уверен, почему C ++ 0x пытается что-то сказать, но это просто означает, что мне нужно прочитать больше статей, написанных Бемом и его друзьями.
Редактировать # 3:
Спасибо, Йоханнес, за то, что справился с моей ленью, набрав "sequenced" в моей строке поиска для чтения PDF.В любом случае я ложился спать и вставал с двумя последними правками… верно; v).
§5.17 / 1, определение операторов присваивания говорит:
Во всех случаях присвоениесеквенируется после вычисления значения правого и левого операндов, а также до вычисления значения выражения присваивания.
Также в §5.3.2 / 1 оператора прединкремента указано
Если x не относится к типу bool, выражение ++ x эквивалентно x + = 1 [Примечание: см. Сложение (5.7) и операторы присваивания (5.17)…].
By++ ++ x
это сокращение от (x +=1) +=1
.Итак, давайте интерпретируем это.
- Оцените
1
на дальнем RHS и спуститесь в парены. - Оцените внутренний
1
, а также значение (prvalue) и адрес(glvalue) из x
. - Теперь нам нужно значение подвыражения + =.
- Мы закончили вычисления значений для этого подвыражения.
- Побочный эффект назначения должен быть секвенирован до того, как станет доступно значение назначения!
- Присвойте новое значение
x
, которое совпадает с результатом подвыражения glvalue и prvalue. - Сейчас мы вне леса.Целое выражение теперь уменьшено до
x +=1
.
Итак, тогда 1 и 3 четко определены, а 2 и 4 - неопределенное поведение, чего и следовало ожидать.
Единственный другой сюрприз, который я обнаружил, выполнив поиск "sequenced" в N3126, был 5.3.4 / 16, где реализации разрешено вызывать operator new
до оценки аргументов конструктора.Это круто.
Правка № 4: (О-о, какая запутанная паутина, которую мы плетем)nnes снова отмечает, что в i == ++i;
значение glvalue (например, адрес) в i
неоднозначно зависит от ++i
. Значение glvalue определенно равно a значению i
, но я не думаю, что 1.9 / 15 предназначено для его включения по той простой причине, что glvalue именованного объекта является константой и не может фактически иметь зависимости .
Для информативного соломника рассмотрим
( i % 2? i : j ) = ++ i; // certainly undefined
Здесь glvalue LHS =
зависит от побочного эффекта на prvalue i
. Адрес i
не обсуждается; исход ?:
есть.
Возможно, хороший контрпример
int i = 3, &j = i;
j = ++ i;
Здесь j
имеет glvalue, отличный от (но идентичный) i
. Это хорошо определено, но i = ++i
нет? Это представляет тривиальное преобразование, которое компилятор может применить к любому случаю.
1,9 / 15 следует сказать
Если побочный эффект на скалярном объекте не секвенирован относительно другого побочного эффекта на том же скалярном объекте или вычисления значения с использованием prvalue того же скалярного объекта, поведение не определено.