Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 403
Завершенные тесты: 2
#1

Order of evaluation - C++

02.07.2016, 00:37. Просмотров 489. Ответов 35
Метки нет (Все метки)

Всем привет. Никак не могу побороть Order of evaluation. В статье на cppreference, приводятся примеры UB и уже на первом я застреваю и не понимаю почему именно так:

If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.
Если побочный эффект для скалярного объекта не упорядочен по отношению к другому побочному эффекту для этого же объекта - поведение не определено

C++
1
i = ++i + i++; // undefined behavior
Собственно тут я не знаю как мыслить. Как подобного рода UB находить в программах? Я пытался применять правила, которые описаны в Secuenced before rule, но ими я не смог объяснить UB приведенного выше примера.

Собственно для примера выше пытался применить правила:

2) The value computations (but not the side-effects) of the operands to any operator are sequenced before the value computation of the result of the operator (but not its side-effects).
-------------------------------------------------------------------------------------------
Вычисление значений (но не побочных эффектов) операндов любого оператора расположены перед вычислением значения оператора в целом (но не его побочного эффекта)

8) The side effect (modification of the left argument) of the built-in assignment operator and of all built-in compound assignment operators is sequenced after the value computation (but not the side effects) of both left and right arguments, and is sequenced before the value computation of the assignment expression (that is, before returning the reference to the modified object)
-------------------------------------------------------------------------------------------
Побочный эффект (изменение левого аргумента) встроенного оператора присваивания и всех встроенных составных операторов присваивания расположены после вычисления значения (но не побочного эффекта) обоих аргументов (левого и правого) и расположены перед вычислением значения оператора присваивания (т.е. перед возвращением ссылки на измененный объект)


Но не нашел противоречий. Помогите понять это. Возможно на примере других выражений.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
02.07.2016, 00:37
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Order of evaluation (C++):

Preprocessing evaluation order - C++
Всем привет! Известно ли в каком порядке препроцессор обрабатывает файлы проекта? Из случая, который со мной сегодня приключился,...

Логические операции и правило Short Circuit Evaluation - C++
Здравствуйте. Прошу помощи, так как мнения по данным вопросам расходятся 1.Какое значение будет принимать х ? #include int...

Пояснение структуры ORDER - C++
Народ помогите разобраться, код мне помогли накалякать с этого форума вот и некоторые непонятные строки есть, и выдает ваще какую то фигню,...

Использование класса ORDER - C++
Следующие задания требуется решить с использованием классов. При этом обязательно оформить методы для выполнения каждого из действий: по...

Описание структуры ORDER - C++
Может помочь с ошибкой и проверить правильно ли все работает)) Описать структуру с именем ORDE: Записи должны быть размещены в алфавитном...

Создать класс Order - C++
Помогите написать задачу пожалуйста 1. Создать класс с именем ORDER, содержащий следующие поля: • расчетный счет плательщика; ...

35
ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 403
Завершенные тесты: 2
02.07.2016, 16:25  [ТС] #16
Цитата Сообщение от Croessmah Посмотреть сообщение
А так постинкремент будет выполнен где-то после.
То есть после "операции" value computation операнда i++, значение i не изменится что ли?
0
Croessmah
Эксперт CЭксперт С++
13419 / 7573 / 855
Регистрация: 27.09.2012
Сообщений: 18,646
Записей в блоге: 3
Завершенные тесты: 1
02.07.2016, 16:28 #17
Цитата Сообщение от ASCII Посмотреть сообщение
То есть выполняем операцию, увеличиваем переменную и возвращаем ее прежнее состояние
Возвращаем прежнее состояние, всё остальное - когда придется.

Добавлено через 39 секунд
Цитата Сообщение от ASCII Посмотреть сообщение
значение i не изменится что ли?
Нет. Оно изменится, скорее всего, где-то уже после выражения в котором стоит постинкремент:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
i = 2;
i2 = i;
//варианты
x = i2 + 1
++i;
i = x;
//или
x = i2 + 1
i = x;
++i;
//или (результат аналогичен первому варианту)
++i;
x = i2 + 1
i = x;
1
ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 403
Завершенные тесты: 2
02.07.2016, 16:31  [ТС] #18
Цитата Сообщение от Croessmah Посмотреть сообщение
Возвращаем прежнее состояние, всё остальное - когда придется.
Ну то что прежнее состояние вернется то понятно, но вот не могу понять, что значит "когда придется"?
Получается когда компилятор вычисляет значения операндов, он не выполняет операции? В конкретном примере на стадии вычисления значения подвыражения i++ он просто читает значение i и не выполняет операцию?
0
Croessmah
Эксперт CЭксперт С++
13419 / 7573 / 855
Регистрация: 27.09.2012
Сообщений: 18,646
Записей в блоге: 3
Завершенные тесты: 1
02.07.2016, 16:32 #19
Цитата Сообщение от ASCII Посмотреть сообщение
и не выполняет операцию?
выполняет, но после, где конкретно - после выражения, конкретнее - не ясно.
Вот от таких "после", "где-то", "как-то" Ваш код не должен зависеть.
То есть i = i++ + 1;
нужно заменить, например, на
C++
1
2
t = i++;
i = t + 1;
здесь порядок задан явно.
0
ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 403
Завершенные тесты: 2
02.07.2016, 16:38  [ТС] #20
C++
1
2
3
4
//варианты
x = i2 + 1
/* ЗДЕСЬ, СМ НИЖЕ */
++i;
А вот там где комментарий вставил, туда компилятор может поместить еще какие-то инструкции по вычислению какой-то другой части выражения?

Добавлено через 1 минуту
Цитата Сообщение от Croessmah Посмотреть сообщение
выполняет, но после, где конкретно - после выражения, конкретнее - не ясно.
Вот от таких "после", "где-то", "как-то" Ваш код не должен зависеть.
То есть i = i++ + 1;
нужно заменить, например, на
C++
1
2
t = i++;
i = t + 1;
здесь порядок задан явно.
Туповат я походу.

Добавлено через 1 минуту
Но ведь само по себе выражение

C++
1
i++ + 1;
Безвредно, в смысле само по себе это не UB, оно становится таковым, когда мы это присваиваем объекту i? Новое выражение в смысле, i = i++ + 1
0
Croessmah
Эксперт CЭксперт С++
13419 / 7573 / 855
Регистрация: 27.09.2012
Сообщений: 18,646
Записей в блоге: 3
Завершенные тесты: 1
02.07.2016, 16:40 #21
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от ASCII Посмотреть сообщение
А вот там где комментарий вставил, туда компилятор может поместить еще какие-то инструкции по вычислению какой-то другой части выражения?
Вполне. В пределах "точки следования"
компилятор творить выполнять всякое разное, что,
по его компетентному мнению, не приведет к изменению результата
Правда, он еще вполне может выражения между собой местами менять,
что может напакостить сильно, но это уже другая тема

Добавлено через 1 минуту
Цитата Сообщение от ASCII Посмотреть сообщение
Безвредно, в смысле само по себе это не UB
Да, это нормальное выражение.
Цитата Сообщение от ASCII Посмотреть сообщение
когда мы это присваиваем объекту i?
Да, потому что не ясно становится что в каком порядке будет вычислено.
поэтому еще раз:
Цитата Сообщение от Croessmah Посмотреть сообщение
не нужно менять значение одного объекта несколько раз в одном выражении (expression, full-expression),
если нет явно выраженного порядка выполнения.
В i = i++ + 1, вы i меняете дважды, причем порядок изменений не определен.
0
ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 403
Завершенные тесты: 2
02.07.2016, 16:41  [ТС] #22
Цитата Сообщение от Croessmah Посмотреть сообщение
В пределах "точки следования"
secuence point rule вроде бы в С++11 уже нету? Его заменили на sequence before rule...
В следствии чего:

C++
1
i = ++i + 1; // undefined behavior (well-defined in C++11)
До С++11 было UB
http://en.cppreference.com/w/cpp/language/eval_order
0
Croessmah
Эксперт CЭксперт С++
13419 / 7573 / 855
Регистрация: 27.09.2012
Сообщений: 18,646
Записей в блоге: 3
Завершенные тесты: 1
02.07.2016, 16:41 #23
Цитата Сообщение от ASCII Посмотреть сообщение
secuence point rule вроде бы в С++11 уже нету? Его заменили на sequence before rule...
Милицию в полицию тоже переименовали
Думаю, смысл высказывания ясен
1
ct0r
Игогошка!
1776 / 678 / 42
Регистрация: 19.08.2012
Сообщений: 1,292
Завершенные тесты: 1
02.07.2016, 16:42 #24
ASCII, забей на компилятор. У него вообще большая свобода действий (в разумных пределах конечно). В стандарте речь не о нем:
The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.
1
Croessmah
Эксперт CЭксперт С++
13419 / 7573 / 855
Регистрация: 27.09.2012
Сообщений: 18,646
Записей в блоге: 3
Завершенные тесты: 1
02.07.2016, 16:52 #25
Цитата Сообщение от ct0r Посмотреть сообщение
забей на компилятор
и на всё остальное тоже?
0
ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 403
Завершенные тесты: 2
02.07.2016, 17:00  [ТС] #26
Цитата Сообщение от Croessmah Посмотреть сообщение
Да, потому что не ясно становится что в каком порядке будет вычислено.
Цитата Сообщение от Croessmah Посмотреть сообщение
В i = i++ + 1, вы i меняете дважды, причем порядок изменений не определен.
Вот тут мы в плотную подошли к моменту, который меня на самом деле до сих пор путает.
Смотрите, имеем общее правило для вычисления операндов какого-либо оператора:

2) The value computations (but not the side-effects) of the operands to any operator are sequenced before the value computation of the result of the operator (but not its side-effects).

То есть просто сказано, что сначала вычисляются операнды, а только потом результат всего оператора. Все.
Далее у нас есть также и частный случай для операторов присвоения.

8) The side effect (modification of the left argument) of the built-in assignment operator and of all built-in compound assignment operators is sequenced after the value computation (but not the side effects) of both left and right arguments, and is sequenced before the value computation of the assignment expression (that is, before returning the reference to the modified object)

Тут уже говорится несколько иначе. Первым делом вычисляются значения операндов оператора присваивания, то есть объект, которому присваивается и "результирующий объект", полученный после вычисления выражения, которое присваивается.

C++
1
a = B; /* где B - любое выражение, не обязательно идентификатор переменной */
Затем, только после вычисления значений этих операндов, происходит side effect левого аргумента.
И УЖЕ ПОСЛЕ ЭТОГО, происходит финальный value computation.

То есть тут получается все упорядочено оказывается? И это сбивает с толку. Ведь если следовать этим правилам (а другие правила тут не работают вроде-бы), то по моим умозаключениям получаем такую картину:

C++
1
2
int i = 0;
i = i++ + 1;
1 Этап - вычисляем операнды.
Поехали:

Первый вариант - сначала i, потом i++ + 1
i == 0 - вычислили, i - просто идентификатор, стоящий слева, не содержит никаких подвыражений.
i++ + 1 - опять, можем считать сначала i++, потом 1, или наоборот, но в данном случае, это не важно.
i++ == 0, i становится равной 1
получаем - 1 + 1.

Второй вариант - сначала i++ + 1, потом i
получим в итоге для i++ + 1 - 1 + 1
но на стадии вычисления i получим 1, но какая разница? Если это затирается?
Ничего не поменяется ведь...
Где-то тут чувствую я ошибаюсь

ОПЕРАНДЫ ВЫЧИСЛИЛИ.


2 Этап - side effect для левого операнда
Тут ясно все, все по порядку, вычислили операнды, и начинаем изменять объект i, присваиваем результат 1 + 1

Ну и финал - возврат ссылки на i, как результата выражения.

Вот и получается, что тут будет 2

Добавлено через 2 минуты
Цитата Сообщение от Croessmah Посмотреть сообщение
Милицию в полицию тоже переименовали
Думаю, смысл высказывания ясен
Смысл то ясен
На самом деле я хотел сказать о другом, что некоторые операции, которые в соответствии с правилом sequence point были UB, могут не являться таковыми в соответствии с правилом sequence before
0
Croessmah
Эксперт CЭксперт С++
13419 / 7573 / 855
Регистрация: 27.09.2012
Сообщений: 18,646
Записей в блоге: 3
Завершенные тесты: 1
02.07.2016, 17:02 #27
Цитата Сообщение от ASCII Посмотреть сообщение
ОПЕРАНДЫ ВЫЧИСЛИЛИ.
Одна поправочка.
Для вычисления значений i++ + 1 достаточно копии i.
Фактически, именно она и будет операндом,
а когда будет вычислено остальное - уже пофигу,
значение i++ + 1 от этого не изменится.
1
ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 403
Завершенные тесты: 2
02.07.2016, 17:03  [ТС] #28
ct0r, ну не компилятор, так абстрактная машина, которая должна обеспечить наблюдаемый результат в соответствии с некими правилами. И вот как раз, почему эта машина делает именно так, а не иначе, я и хочу понять)
0
ct0r
Игогошка!
1776 / 678 / 42
Регистрация: 19.08.2012
Сообщений: 1,292
Завершенные тесты: 1
02.07.2016, 17:06 #29
Croessmah, как вариант. Зачем нужно писать всякие ++ в выражениях, если это можно просто написать отдельно, что читабельнее и менее подвержено ошибкам? Разве что чужой быдлокод читать?
0
ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 403
Завершенные тесты: 2
02.07.2016, 17:06  [ТС] #30
Croessmah, про копию помню, я ее тут сознательно не упомянул, ибо
Цитата Сообщение от Croessmah Посмотреть сообщение
значение i++ + 1 от этого не изменится.
Что кстати и путает. Ведь если значение выражения не меняется, а порядок для оператора = задан.
То чем это отличается от, например

C++
1
i = 2;
Ведь все равно значение i затрется результатом выражения.
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
02.07.2016, 17:06
Привет! Вот еще темы с ответами:

Описать структуру с именем ORDER - C++
Описать структуру с именем ORDER, содержащую следующие поля: расчетный счет плательщика; расчетный счет получателя; перечисляемая сумма в...

Описать структуру с именем Order - C++
1. Разработать программный блок, который позволяет выполнять обработку динамического массива структур. Предусмотреть возможность создания,...

Описать структуру с именем Order - C++
Дорогие форумчане =) мне нужна ваша помощь. Нужно написать программу,первую часть сделал сам. #include <iostream> #include <iomanip> ...

Перевести структуру ORDER в класс - C++
Помогите решить! Требуется решить задачу с использованием классов. При этом обязательно оформить методы для выполнения каждого из...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
30
Yandex
Объявления
02.07.2016, 17:06
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru