Являются ли множественные мутации в списке инициализаторов неопределенным поведением?

Мне интересно узнать списки инициализаторов и точки последовательности. Некоторое время назад я читал, что порядок оценки в списках инициализаторов оставлен вправо. Если это так, то между точками оценки должна быть какая-то точка последовательности, не так ли? Итак, с этим сказал следующий действующий код? Есть ли что-то, что вызывает неопределенное поведение в нем?

int i = 0; struct S { S(...) {} operator int() { return i; } }; int main() { i = S{++i, ++i}; } 

Любые ответы принимаются.

Да, код действителен и не имеет неопределенного поведения. Выражения в списке инициализаторов оцениваются слева направо и упорядочиваются перед оценкой конструктора S Поэтому ваша программа должна последовательно присваивать значение 2 переменной i .

Цитируя § 8.5.4 стандарта C ++:

«В списке инициализаторов списка с привязкой к инициализации предложения инициализатора, включая все, что вытекает из расширений пакетов (14.5.3), оцениваются в том порядке, в котором они отображаются . То есть, вычисление каждого значения и сторона эффект, связанный с заданным предложением инициализатора, секвенирован перед каждым вычислением значения и побочным эффектом, связанным с любым предложением инициализатора, которое следует за ним в списке списка инициализаторов, разделенных запятыми ».

Таким образом, происходит следующее:

  1. ++i получает оценку, давая i = 1 (первый аргумент S -конструктора);
  2. ++i получает оценку, давая i = 2 (второй аргумент S -конструктора);
  3. S конструктор S ;
  4. Оператор преобразования S выполняется, возвращая значение 2 ;
  5. значение 2 присваивается i (которое уже имеет значение 2 ).

Другим важным пунктом Стандарта является § 1.9 / 15, в котором также упоминаются аналогичные примеры, которые имеют неопределенное поведение:

 i = v[i++]; // the behavior is undefined i = i++ + 1; // the behavior is undefined 

Однако в том же абзаце говорится:

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

Поскольку 1) оценка выражений в списке инициализаторов секвенирована слева направо, 2) выполнение конструктора S секвенируется после оценки всех выражений в списке инициализаторов и 3) присвоение i является после выполнения конструктора S (и его оператора преобразования), поведение корректно определено.

Да, действительно, у вас есть случай неопределенного поведения.

Ниже приведены примеры ситуаций, вызывающих неопределенное поведение:

  • Переменная изменяется несколько раз в пределах одной точки последовательности . В качестве канонического примера часто упоминается выражение i = i ++, когда одновременно выполняются присвоение переменной i и ее приращение. Чтобы узнать больше об этих ошибках, прочитайте раздел «Точки последовательности» .
  • Использование переменной перед ее инициализацией. Неопределенное поведение возникает при попытке использовать переменную.
  • Распределение памяти с использованием нового оператора [] и последующего выпуска с использованием оператора удаления. Например: T * p = new T [10]; удалить p ;. Правильный код: T * p = new T [10]; delete [] p ;.

РЕДАКТИРОВАНИЕ

Также ваш код S {++ i, ++ i}; не компилируется для VS2012. Может быть, вы имеете в виду S (++ i, ++ i) ;? Если вы используете «()», то присутствует неопределенное поведение. В другом случае ваш исходный код неверен.

  • Почему это неопределенное поведение для удаления массива производных объектов с помощью базового указателя?
  • Арифметический сдвиг вправо дает фиктивный результат?
  • Как объяснить неопределенное поведение новичков-новичков?
  • Это бесконечная recursion UB?
  • Сопоставлено ли целочисленное переполнение по-прежнему неопределенным поведением в C ++?
  • Каков правильный способ ввода чисел - поплавок в int и наоборот?
  • Почему char * вызывает неопределенное поведение, а char - нет?
  • Действительно ли «Неопределенное поведение» действительно позволяет * что-либо * произойти?
  • Как переменная по тому же адресу производит 2 разных значения?
  • Когда вызов функции-члена в экземпляре null приводит к неопределенному поведению?
  • Каковы все общие неопределенные типы поведения, о которых должен знать программист на C ++?
  • Interesting Posts

    Как я могу физически уничтожить данные с отказавшего жесткого диска?

    ggplot bar plot с фасет-зависимым порядком категорий

    Несколько вызовов ajax в одно и то же время

    Как убить процесс, который в настоящее время использует порт на localhost в Windows?

    В чем разница между SessionState и ViewState?

    Любая хорошая утилита для отслеживания исходящего трафика и запросов от Win PC?

    Будет ли использовать один и тот же пароль для Windows 7 и Ubuntu, чтобы он стал проще взломать?

    Эффективное вычисление линейной комбинации столбцов data.table

    Могу ли я создать новый сеанс в другой вкладке или окне в Google Chrome?

    Как загрузить локальный файл на сервер через терминал Linux

    Как я могу запланировать службу Windows C # для выполнения задачи ежедневно?

    Как сбросить пароль администратора виртуальной машины Windows XP, работающей в VMWare?

    В чем разница между HTTP и REST?

    WPF ContextMenu woes: Как установить DataContext для ContextMenu?

    Как загрузить файл и сохранить его в Stream для дальнейшего просмотра с помощью C #?

    Давайте будем гением компьютера.