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

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

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

Order of evaluation - C++

02.07.2016, 00:37. Просмотров 508. Ответов 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
Croessmah
Ушел
Эксперт CЭксперт С++
13553 / 7704 / 872
Регистрация: 27.09.2012
Сообщений: 19,006
Записей в блоге: 3
Завершенные тесты: 1
02.07.2016, 11:53 #2
C++
1
i = ++i + i++; // undefined behavior
А попробуйте побыть на месте компилятора.
В какой последовательности вы выполните этот код?
1
ASCII
90 / 63 / 10
Регистрация: 15.12.2013
Сообщений: 407
Завершенные тесты: 2
02.07.2016, 13:59  [ТС] #3
Croessmah, ну во-первых посмотрел бы на две части оператора =.

1) вычислил бы i (которая слева, value computation)
2) ++i + i++ ==> начал бы вычислять сперва значения операндов и наткнулся бы на:


4) The value computation of the built-in post-increment and post-decrement operators is sequenced before its side-effect.
-----------------------------------------------------------------------------------------------
Вычисление значение у встроенного постфиксного оператора инкремента расположено перед его побочным эффектом

5) The side effect of the built-in pre-increment and pre-decrement operators is sequenced before its value computation (implicit rule due to definition as compound assignment)
-----------------------------------------------------------------------------------------------
Тут тоже самое, только наоборот, побочный эффект перед вычислением значения


Но вроде как нету правила, которое мне (компилятору), диктует какой из операндов я должен вычислять первым.
Поэтому я могу поступить двумя способами:

1)

вычислить сперва ++i
вычислить i++
вычислить их сумму

2)

вычислить i++
вычислить ++i
вычислить их сумму

Но тут у оператора + операнды (++i) и (i++), поэтому вычислить значения операндов можно только с побочным эффектом, то есть выполняя операторы инкремента.

Таким образом, допустим если i изначально была равна 10

В первом варианте получается 23
Во втором варианте получается 22.

Еп, походу наличие двух вариантов у компиляторов и приводит к UB?
Какую-то длинную цепочку мыслей я построил...
0
Ferrari F1
619 / 513 / 101
Регистрация: 27.01.2015
Сообщений: 2,981
Записей в блоге: 1
Завершенные тесты: 1
02.07.2016, 14:17 #4
ASCII, как много времени уйдет, чтобы читать и вполне сразу понимать все эти статьи на английском?
0
ASCII
90 / 63 / 10
Регистрация: 15.12.2013
Сообщений: 407
Завершенные тесты: 2
02.07.2016, 14:27  [ТС] #5
Если я правильно расписал пример выше, то как быть вот с этим?

C++
1
i = i++ + 1; // undefined behavior (but i = ++i + 1; is well-defined)
Добавлено через 3 минуты
Ferrari F1, это же от человека зависит, тут на мой взгляд играет роль:

1) Уровень знаний английского
2) Опыт в той области о которой читаешь
3) Ну и наверное целеустремленность

Я вот люблю докапываться до сути, наткнулся на такую проблему, теперь по справке со стандарта и cppreference пытаюсь досканально разобраться.

Добавлено через 2 минуты
Ferrari F1, а на счет сразу - трудно, тем более если только изучаешь английский, но по мере чтения на английском "выучиваются" слова и с каждым разом замечаешь, что уже читаешь и не задумываешься над переводом все дольше и дольше, не воспользовавшись переводчиком
0
Ferrari F1
619 / 513 / 101
Регистрация: 27.01.2015
Сообщений: 2,981
Записей в блоге: 1
Завершенные тесты: 1
02.07.2016, 14:32 #6
ASCII,
я просто думал, что все, кто выкладывают тут выдержки на английском, довольно неплохо его понимают при чтении информации технического плана (именно технического, а не разговорного или литературного, где могут содержаться всякие идиомы или двусмысленные обороты).

То есть это вполне нормально, что первое некоторое время придется с гугл переводчиком посидеть-попереводить каждое третье слово?
0
ASCII
90 / 63 / 10
Регистрация: 15.12.2013
Сообщений: 407
Завершенные тесты: 2
02.07.2016, 14:38  [ТС] #7
Croessmah, вот тот пример, который я расписал, вроде бы объясняется этим
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++ + 1; // undefined behavior (but i = ++i + 1; is well-defined)
Вообще вроде над i side effect должен быть упорядочен?


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)


То есть вычислить значения выражений i и i++ + 1, затем изменить i, затем сделать value computation для всего assignment выражения.

Добавлено через 1 минуту
Ferrari F1, пффф, я неделю назад чуть ли ни каждое слово гуглил. Сейчас вроде нормально читаю The Art of Multiprocessor Programming, а она только на английском. Конечно все равно приходится лезть в переводчик, но уже 1 раз на целый абзац.
0
Croessmah
Ушел
Эксперт CЭксперт С++
13553 / 7704 / 872
Регистрация: 27.09.2012
Сообщений: 19,006
Записей в блоге: 3
Завершенные тесты: 1
02.07.2016, 15:12 #8
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от ASCII Посмотреть сообщение
Какую-то длинную цепочку мыслей я построил...
Иногда это необходимо
Цитата Сообщение от ASCII Посмотреть сообщение
Еп, походу наличие двух вариантов у компиляторов и приводит к UB?
Ну вот видите, уже два варианта накопилось,
значит определить однозначно конечное значение тоже нельзя
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
То есть это вполне нормально, что первое некоторое время придется с гугл переводчиком посидеть-попереводить каждое третье слово?
Я почти не знаю английский, как бы странно это не звучало
1
ASCII
90 / 63 / 10
Регистрация: 15.12.2013
Сообщений: 407
Завершенные тесты: 2
02.07.2016, 15:15  [ТС] #9
Цитата Сообщение от Croessmah Посмотреть сообщение
Ну вот видите, уже два варианта накопилось,
значит определить однозначно конечное значение тоже нельзя
Спасибо за наставление на путь истинный , но как рассуждать с остальными примерами? Вот в частности с тем, который я привел в качестве следующего.
0
Ferrari F1
619 / 513 / 101
Регистрация: 27.01.2015
Сообщений: 2,981
Записей в блоге: 1
Завершенные тесты: 1
02.07.2016, 15:18 #10
Цитата Сообщение от Croessmah Посмотреть сообщение
Я почти не знаю английский, как бы странно это не звучало
Меня это обнадеживает)) Точно могу считать, что уметь понимать - это одно, а самому писать или говорить - совсем другое, куда сложнее)
0
Croessmah
Ушел
Эксперт CЭксперт С++
13553 / 7704 / 872
Регистрация: 27.09.2012
Сообщений: 19,006
Записей в блоге: 3
Завершенные тесты: 1
02.07.2016, 15:22 #11
Цитата Сообщение от ASCII Посмотреть сообщение
но как рассуждать с остальными примерами?
Со всеми примерами рассуждайте так:
не нужно менять значение одного объекта несколько раз в одном выражении (expression, full-expression),
если нет явно выраженного порядка выполнения.
1
ASCII
90 / 63 / 10
Регистрация: 15.12.2013
Сообщений: 407
Завершенные тесты: 2
02.07.2016, 15:26  [ТС] #12
Croessmah, это понятно, но ведь это не всегда так:

C++
1
i = ++i + 1; // well defined
Я преследую цель, понять, где можно так поступать, а где нет и почему именно так...
Вот казалось бы, разница между:

C++
1
i = ++i + 1; // well defined
и

C++
1
i = i++ + 1; // undefined behavior
Всего лишь в порядке value computation и side effect для операнда оператора +, но одно работает нормально, а другое UB...
Хотя и там и там в одном выражении есть 2 side effect'a для i.
0
Croessmah
Ушел
Эксперт CЭксперт С++
13553 / 7704 / 872
Регистрация: 27.09.2012
Сообщений: 19,006
Записей в блоге: 3
Завершенные тесты: 1
02.07.2016, 15:53 #13
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от ASCII Посмотреть сообщение
это понятно, но ведь это не всегда так
Поэтому я написал:
Цитата Сообщение от Croessmah Посмотреть сообщение
если нет явно выраженного порядка выполнения
Цитата Сообщение от ASCII Посмотреть сообщение
Вот казалось бы, разница между
В выражении i = ++i + 1; в любом случае инкремент будет выполнен при вычислении,
и уже потом будет выполнено присванивание, т.е. порядок вычисления задан.
А при
Цитата Сообщение от ASCII Посмотреть сообщение
C++
1
i = i++ + 1;
попробуйте снова встать на место компилятора.
В каком порядке должны идти присваивание и инкремент?
Сначала присвоить значение i, а потом увеличить значение на 1,
или же сначала увеличить значение, а потом выполнить присваивание?
Разложим выражение i = i++ + 1;, возьмем i равную 2:
C++
1
2
3
4
5
6
7
8
9
10
//раскладываем:
i++ + 1;//значение выражения равно 3, осталось выполнить инкремент и присваивание
//сделать так:
i = 3;
i += 1;
//и получить i равную 4
//или же сделать так:
i += 1;
i = 3;
//и получить i равную 3
http://rextester.com/RTWN92621
http://rextester.com/JDV61087
1
ASCII
90 / 63 / 10
Регистрация: 15.12.2013
Сообщений: 407
Завершенные тесты: 2
02.07.2016, 16:13  [ТС] #14
Croessmah, А вот если рассмотреть такое выражение:

C++
1
i++ + 1;
Вопрос:

Согласно этому правилу - 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).

Как будут получаться значения операндов оператора +?
А точней мне интересен такой момент:

1) Вычисляем 1 - все ясно, просто берем константу
2) Вычисляем i++ - ВОТ ТУТ, что тут произойдет? То есть операнд оператора + это подвыражение i++, чтобы вычислить его значение, его же необходимо полностью выполнить? То есть выполняем операцию, увеличиваем переменную и возвращаем ее прежнее состояние, согласно правилу выполнения постфиксного инкремента - это и будет процесс value computation для этого операнда? То есть невозможна такая ситуация, что компилятор просто прочтет значение i не выполняя ++?
0
Croessmah
Ушел
Эксперт CЭксперт С++
13553 / 7704 / 872
Регистрация: 27.09.2012
Сообщений: 19,006
Записей в блоге: 3
Завершенные тесты: 1
02.07.2016, 16:24 #15
Цитата Сообщение от ASCII Посмотреть сообщение
чтобы вычислить его значение, его же необходимо полностью выполнить?
У Вас же в вычислениях дальше участвует копия i.
А инкремент будет выполнен где-то после.
И в данном случае, от этого "где-то" будет зависеть конечное значение i.
The value of a postfix ++ expression is the value of its operand. [ Note: the value obtained is a copy of the original value — end note ] The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type or a pointer to a complete object type. The value of the operand object is modified by adding 1 to it, unless the object is of type bool, in which case it is set to true. [ Note: this use is deprecated, see Annex D. — end note ] The value computation of the ++ expression is sequenced before the modification of the operand object. With respect to an indeterminately-sequenced function call, the operation of postfix ++ is a single evaluation. [ Note: Therefore, a function call shall not intervene between the lvalue-to-rvalue conversion and the side effect associated with any single postfix ++ operator. — end note ] The result is a prvalue. The type of the result is the cv-unqualified version of the type of the operand. See also 5.7 and 5.17.
0
02.07.2016, 16:24
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
02.07.2016, 16:24
Привет! Вот еще темы с ответами:

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

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