Я читаю n3290 черновик стандарта С++ 11 (как можно ближе к фактическому стандартному тексту), и я заметил, что i = i++ + 1;
создает поведение undefined. Раньше я видел подобные вопросы, но на них отвечали более старые стандарты (точки последовательности). Новый стандарт вводит вместо этого концепцию секвенирования до/после отношения между выражениями и выполнением подвыражений.
1.9 13 Последовательность перед этим является асимметричным, транзитивным, парным отношением между оценками, выполненными одним потоком (1.10), который индуцирует частичный порядок среди этих оценок. При любых двух оценках A и B, если A секвенирован до B, то исполнение A должно предшествует исполнению B. Если A не секвенирован до того, как B и B не секвенированы до A, то A и B не подвержены влиянию. [ Обратите внимание выполнение необязательных оценок может перекрываться. -end note] Оценки A и B неопределенно секвенированы, когда либо A является секвенирован до того, как B или B секвенирован до A, но он не определен который. [Примечание: неопределенные последовательности оценок не могут перекрываться, но либо можно было выполнить в первую очередь. -end note]
1.9 14 Каждое значение вычисление и побочный эффект, связанные с полным выражением секвенированы перед каждым вычислением значения и связанным с ним побочным эффектом с последующим вычислением следующего выражения.
1.9 15 За исключением случаев, когда отметили, что оценки операндов отдельных операторов и подвыражения отдельных выражений неощутимы. [Примечание: в выражение, которое оценивается более одного раза во время выполнения программа, необоснованные и неопределенно упорядоченные оценки его подвыражения не должны выполняться последовательно в разных оценки. -end note] Вычисления значений операндов оператор упорядочивается перед вычислением значения результата Оператор. Если побочный эффект скалярного объекта не подвержен относительно какого-либо другого эффекта на том же скалярном объекте или вычисление значения с использованием значения одного и того же скалярного объекта, поведение undefined.
[ Example:
void f(int, int);
void g(int i, int* v) {
i = v[i++]; // the behavior is undefined
i = 7, i++, i++; // i becomes 9
i = i++ + 1; // the behavior is undefined
i = i + 1; // the value of i is incremented
f(i = -1, i = -1); // the behavior is undefined
}
—end example ]
Как я понимаю, он работает так:
-
operator=
имеет два выражения операндов: ссылаясь наi
иi++ + 1
, оба не привязаны друг к другу. Второй имеет побочный эффект наi
, но первый кажется мне не иметь побочного эффекта или использоваться при вычислении значения (или ссылается на "вычисление значения с использованием значения одного и того же скалярного объекта"? на самом деле зависит от значения, хранящегося в i? не так думайте), так что это не поведение undefined; -
operator=
выполнение выполняется после обеих операндов. Он имеет побочный эффект наi
, но он хорошо упорядочен по отношению к обоим операндам, так что это не udefined поведение; -
i++ + 1
- это явно определенное поведение.
Я что-то не так? Или это поведение линии undefined по какой-то другой причине?
PS. Стандарт фактически говорит
Вычисления значений операндов оператора секвенированы перед вычислением значения результата оператора.
и он вообще не упоминает побочные эффекты в этом контексте. Однако отношение секвенирования определяется только между оценками выражений и оценкой = вычислением значения + побочными эффектами. Поэтому либо я должен предположить, что этот проект здесь несовместим, либо предположим, что в этой строке они означают оценку вместо вычисления стоимости. Или я здесь не прав?
EDIT:
Думаю, я отвечу на себя здесь, но в этом причина моей путаницы:
5 1 Выражение представляет собой последовательность операторов и операндов, которые задает вычисление. Выражение может привести к значению и может вызывают побочные эффекты.
Таким образом, операнды операторов не являются самими суб-выражениями. Поэтому вычисляется только вычисление значения для целых i = i++ + 1;
, и не упоминается о секвенсировании побочных эффектов стандартом. Вот почему он undefined.
Обратите внимание, что если, например, operator=
был перегружен для заданного типа (так что это будет вызов функции implicite), это не будет поведение undefined, правильно?