Изменить: еще не ответил - связанный вопрос касался обычных r-значений, списки инициализаторов - это отдельная, если связанная концепция.

Этот оператор четко определен или использует оператор приращения префикса в списке инициализаторов для переменной, которая дважды появляется в списке, неопределенное поведение?

struct T t = { i, ++i };

Меня больше всего интересует ANSI C, но было бы полезно узнать, отличаются ли другие версии C и / или C ++. И если допустимы подобные конструкции, подобные приведенным ниже:

struct T t = { i, i++ };

struct T t = { ++i, ++i };

struct T t = { i++, ++i };

struct T t = { i++, i++ };
17
Ray Hamel 6 Сен 2016 в 06:04

3 ответа

Лучший ответ

C

В C (не обязательно тот же ответ, что и для C ++) нет точек последовательности, связанных с компонентами списка инициализаторов.

Стандарт C11, ISO / IEC 9899: 2011, говорит в разделе §6.7.9 Инициализация :

¶19 Инициализация должна происходить в порядке списка инициализаторов, каждый инициализатор, предусмотренный для конкретного подобъекта, отменяет любой ранее перечисленный инициализатор для того же подобъекта; 151)

151) Любой инициализатор для подобъекта, который переопределен и поэтому не используется для инициализации этого подобъекта, может вообще не оцениваться.

Звучит многообещающе, но ...

¶23 Вычисления выражений списка инициализации неопределенно упорядочены относительно друг друга, и поэтому порядок, в котором возникают какие-либо побочные эффекты, не указан. 152)

152) В частности, порядок оценки не обязательно должен совпадать с порядком инициализации подобъекта.

Итак, (в C) порядок оценки является неопределенным, и вы не можете полагаться на то, когда происходят приращения (или, в крайних случаях, не проиллюстрированных кодом в вопросе, происходят ли приращения).

В C99 (ISO / IEC 9899: 1999) номер раздела - §6.7.8, но параграфы 19 и 23 имеют практически одинаковое содержание, за исключением того, что номера сносок разные.

В C90 (ISO / IEC 9899: 1990) проблема не решается явно.

C ++

Судя по ответу < / a> правила в C ++ 11 (и более поздних версиях) отличаются от правил в C11. Подобные вещи подчеркивают, что языки C и C ++ различны, и чрезвычайно затрудняют написание исчерпывающих ответов на вопросы, помеченные обоими языками.

Близко связанные вопросы

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

Оба были отмечены πάντα ῥεῖ в комментариях.

13
Community 20 Июн 2020 в 09:12

В C11 поведение всех этих инициализаций не определено. См. 6.7.9 / 23:

Вычисления выражений списка инициализации неопределенно упорядочены по отношению друг к другу, и поэтому порядок, в котором возникают какие-либо побочные эффекты, не указан.

Термин неопределенная последовательность определяется как таковой (5.1.2.3):

Оценки A и B имеют неопределенную последовательность, если последовательность A находится либо до, либо после B, но не указано, какая именно.

В C99 использованный язык не был четко сформулирован относительно того, является ли это той же ситуацией или неопределенным поведением. В C89 проблема вообще не упоминается, поэтому мы, вероятно, должны предположить, что в C89 они не определены.

6
M.M 6 Сен 2016 в 03:26

C ++ 11 и новее

Поведение четко определено для инициализации списка. В соответствии с правилами последовательности до (начиная с C ++ 11):

10) При инициализации списка каждое вычисление значения и побочный эффект данного предложения инициализатора упорядочиваются перед каждым вычислением значения и побочным эффектом, связанным с любым предложением инициализатора, которое следует за ним в заключенном в фигурные скобки списке инициализаторов, разделенных запятыми.

Итак, для struct T t = { i, ++i }; сначала будет оцениваться i, а затем ++i, порядок четко определен. И все остальные образцы тоже подойдут.

Цитаты из стандарта C ++, $ 8.6.4 / 4 Инициализация списка [dcl.init.list]:

(курсив мой)

В списке инициализаторов списка инициализации в фигурных скобках предложения-инициализаторы, включая все, что является результатом расширения пакета ([temp.variadic]), оцениваются в том порядке, в котором они появляются . То есть каждое вычисление значения и побочный эффект, связанный с заданное предложение-инициализатор упорядочивается перед каждым вычислением значения и побочный эффект, связанный с любым предложением инициализатора, которое следует за ним в списке инициализаторов, разделенных запятыми. [Примечание: это порядок оценки сохраняется независимо от семантики инициализация; например, это применяется, когда элементы список-инициализаторов интерпретируются как аргументы вызова конструктора, даже если обычно нет ограничений последовательности на аргументы звонка. - конец примечания]

15
songyuanyao 6 Сен 2016 в 04:03