И «это дает ожидаемый результат» - не повод думать, что это определенное поведение. Возвращение того, что я ожидаю, является одним из возможных результатов неопределенного поведения.

аю этоответ о неопределенном поведении, где я увидел следующее утверждение:

++++++i;     // UB, parsed as (++(++(++i)))

Я не думаю, что это неопределенное поведение. У меня есть сомнения, действительно ли это UB в C ++? Если да, то как?

Также я сделал программу и скомпилировал используяg++ prog.cpp -Wall -Wextra -std=gnu++1z -pedantic команда работает нормально без предупреждения. Это дает ожидаемый результат.

#include <iostream>
using namespace std;

int main()
{
    int i = 0;
    cout<<++++++i<<endl;
}
 VTT01 дек. 2017 г., 21:10
Кажется, что он четко определен и эквивалентен (немного псевдокод)i.operator++().operator++().operator++()нет способа изменить порядок выполнения этих операторов, потому что каждый следующий вызов зависит от возвращаемого значения предыдущего вызова.
 Carlos01 дек. 2017 г., 21:13
Но тот факт, что он печатает правильное число, не означает, что это не UB. Там могут быть некоторые интерпретации языка, где может быть напечатано что-то еще, или исключение.
 DeiDei01 дек. 2017 г., 21:07
Не похоже на UB для меня. Даже если разобрать как таковой. Оценка должна происходить вовне.
 Ron01 дек. 2017 г., 21:13
Возможно, это был UB в эпоху до C ++ 11. В последующем ответе упоминается отсутствие точек последовательности в стандарте C ++ 11, что делает вышеуказанное хорошо определенным поведением.
 StoryTeller01 дек. 2017 г., 21:16
Самые противные конструкции часто выглядят как UB. Хороший!

Ответы на вопрос(2)

Решение Вопроса

зличными предварительными приращениями нет последовательности. Еслиi был пользовательский тип, это было бы хорошо определенное поведение, потому что тогда был бы вызов функции (точка последовательности).

В C ++ 11 идея точек последовательности была заменена на последовательность до / после после. Дефект 637 (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#637) предоставляет пример того, как ранее неопределенная конструкция стала четко определенной (i = ++i + 1).

Чтобы понять, почему это не неопределенное поведение, давайте посмотрим на части, которые нам нужны.++i эквивалентноi = i + 1 (Кромеi оценивается только один раз). Далее, если мы подставимi = i + 1 с участиемinc, ++(i = i + 1) становитсяinc = inc + 1.

[expr.ass] сообщает:

Во всех случаях присваивание выполняется после вычисления значения правого и левого операндов и до вычисления значения выражения присваивания.

Таким образом, назначение вi = i + 1 последовательность перед вычислением значенияinc; однако назначение вinc = inc + 1 последовательностьпосле расчет стоимостиinc, Там нет неопределенного поведения, потому что назначения являются последовательными.

 Peter01 дек. 2017 г., 21:51
@VTT - До C ++ 11 вызов встроенных операторов не всегда подразумевал упорядочение - и изменение переменной дважды в одном выражении, например, увеличение ее вдвое, поэтому всегда давало неопределенное поведение. Встроенные операторы по основным типам (например,int) не включают вызовы функций - поэтому невозможно изменитьoperator+() на основных типах (например, невозможно изменить добавлениеintы делать вычитание)
 user904100101 дек. 2017 г., 22:07
@Peter Per [expr.ass] / 7,E1 op= E2 эквивалентноE1 = E1 op E2 КромеE1 оценивается только один раз. Смотрите остальную часть моего ответа о том, как все остальное упорядочено.
 VTT01 дек. 2017 г., 22:15
@Peter Видите ли, встроенные операторы называютсяфункции (по крайней мере, в недавних стандартах), если бы они были чем-то иным, чем функциями в более старых стандартах, то я бы посчитал это более радикальным изменением, чем все эти изменения правил последовательности в целом.
 VTT01 дек. 2017 г., 21:40
Таким образом, вызов встроенных операторов не являются точками последовательности? а встроенные операторы не являются функциями?

хотя трудно представить, как с ним можно обращаться неправильно. Но до C ++ 11 это не было определено, поскольку один и тот же объект изменялся несколько раз без указания промежуточной последовательности.

Можно представить себе компилятор, который «оптимизировал» код, объединив все модификации вi, Таким образом, каждый шаг увеличивается, увеличивая исходное значение. Но дело не в этом. UB - это UB, если стандарт так говорит. Не имеет значения, можем ли мы представить, как это может потерпеть неудачу.

 gnasher72902 дек. 2017 г., 13:55
И «это дает ожидаемый результат» - не повод думать, что это определенное поведение. Возвращение того, что я ожидаю, является одним из возможных результатов неопределенного поведения.
 gnasher72902 дек. 2017 г., 13:54
Тем не менее, важным моментом является то, что что-то может быть неопределенным поведением, не имея представления о том, что может пойти не так. Например, int i = 1; int j = (++ i) + (++ i); является неопределенным поведением. Кто-то может поспорить, что «он вернет либо 2 + 3, либо 3 + 2, поэтому он определен, чтобы установить для j значение 5, тогда как (++ i) - (++ i) может вернуть 2 - 3 или 3 - 2, поэтому он не определен. ", но это всегда не определено.
 Shafik Yaghmour01 дек. 2017 г., 21:55
видетьмой комментарий выше было много вещей, которые стали хорошо определены в C ++ 11

Ваш ответ на вопрос