Рассмотрим следующий код:ли множественные мутации одного и того же переменной в списках инициализаторов неопределенное поведение предварительно 11
int main()
{
int count = 0 ;
int arrInt[2] = { count++, count++ } ;
return 0 ;
}
Если скомпилировать код, используя clang -std=c++03
производит следующее предупреждение (live example):
warning: multiple unsequenced modifications to 'count' [-Wunsequenced]
int arrInt[2] = { count++, count++ } ;
^ ~~
Я не защищаю для такого кода, но подобный код подошел другой вопрос и есть разногласия по поводу того, оно определено или нет в соответствии со стандартом pre-C++ 11. В C++ 11 это поведение хорошо определено в соответствии с Are multiple mutations within initializer lists undefined behavior, и действительно, если я использую -std=c++11
, тогда предупреждение уходит.
Если мы посмотрим на пред- 11draft standardC++ это не один и тот же язык, охватывающий инициализатора-лист так, кажется, мы остались с Chapter 5
Выражения пункта , который говорит:
За исключением тех случаев, когда отмечено, порядок оценки операндов отдельных операторов и подвыражений отдельных выражений и порядок, в котором происходят побочные эффекты, не определены. 57) Между предыдущей и следующей точками последовательности скалярный объект должен иметь значение, которое его хранимое значение изменялось не более одного раза путем оценки выражения. Кроме того, к предыдущему значению следует обращаться только для определения значения, которое необходимо сохранить. Требования настоящего параграфа удовлетворяются для каждого допустимого упорядочения подвыражений полного выражения; в противном случае поведение не определено.
Для того, чтобы это было неопределенные, казалось бы, мы бы интерпретировать count++, count++
как выражение и поэтому каждый count++
как подвыражения, поэтому этот код неопределенный предварительно C++ 11?
Интересно. Казалось бы, существенным моментом является то, что выражения в истинном списке инициализаторов считаются полными выражениями, потому что невозможно найти более крупную структуру с «выражением» в ее имени, которое их содержит. Это актуально, потому что синтаксически _initializer-list_ также используется для _expression-list_, что также встречается в вызовах функций для экземпляра. Там ** является ** охватывающим выражением (_postfix-expression_ для полного вызова функции), так что отдельные аргументы не считаются полными выражениями, и после них нет точек последовательности. –
@MarcvanLeeuwen, это правильно, я всегда хотел добавить раздел, объясняющий, почему это отличается от вызова функции. Я рад, что вы смогли это понять, это всегда полезный опыт. –