Re[5]: приоритеты перегрженных операций
От: LaptevVV Россия  
Дата: 07.07.04 05:02
Оценка: 2 (2)
Здравствуйте, Аноним, Вы писали:

А>1.Правильно ли я понял что неопределенное поведение возникает только при модификации переменной в выражении больше одного раза?

Нет, в стандарте не так написано. Там определены так называемые "точки следования". Этот вопрос уже очень подробно обсуждался — поичи по этим словам. Или напрямую обратись к экспертам (Павел Кузнецов, и Андрей Тарасевич) — они точно эти посты укажут, поскольку активно в них участвовали.
А>2.Означает ли это что если я не модифицирую переменную в выражении больше 1 раза то я могу быть уверен что выражение будет работать одинаково на всех компиляторах?
Смотри сюда — я написал небольшой ликбез в своей книге

Как указано в стандарте языка С++, порядок вычисления подвыражений внутри выражений не определен. Не стоит полагаться на то, что вычисления выражений выполняются слева направо. Это не противоречит приоритету операций. Пусть у нас в программе написано выражение,

a = b + c + d;

где b, c и d сами являются выражениями. Операция сложения действительно будут выполняться слева направо, то есть сначала к b прибавится с, а потом к результату прибавится d. Однако порядок вычислений выражений b, c и d — не определен. Компилятор может сначала вычислить с, затем d и только потом b. Собственно, ну и пусть, скажете вы. Однако не все так просто. Рассмотрим несколько искусственный, но простой пример:
int i = 1, k = 2, j = 3;
i = (i=j-k) + (i=j+k);
cout << i << endl;

Ничего «криминального» не наблюдается, системы фирмы Borland (Borland C++ 3.1, Borland C++ 5, Borland C++ Builder 6) во всех режимах трансляции выдают один и тот же результат 6. Поменяв местами слагаемые
i = (i=j+k) + (i=j-k);

тоже во всех вариантах получаем 6. Вроде бы все логично: независимо от порядка вычисления выражение j-k должно иметь значение 1, а j+k равно 5. Поэтому результат получается равным 6. Если бы я писал транслятор, я именно так и рассуждал бы при реализации арифметических выражений. Однако разработчики Visual C++ 6 думали иначе: то же выражение
i = (i=j-k) + (i=j+k);

в этой среде имеет значение 10. А если поменять слагаемые местами, тогда результат получается равным 2. Такие ситуации в стандарте называются undefined behaviour — неопределенное поведение. Основной отличительной чертой является неоднократное присваивание одной и той же переменной в пределах одного выражения. Например, следующее выражение является как раз таким:
(a+=b)+=a;

Какое значение переменной а будет добавляться к результату в скобках: то, которое было до изменения а или уже измененное? Неопределенное поведение может проявляться не только в операциях с присваиванием, но и при использовании инкремента или декремента. Например, оператор
i = ++i + 1;

является примером из стандарта, демонстрирующим неопределенное поведение. Вообще-то говоря, невинные, на первый взгляд, выражения
++++i; (++i)++;

тоже отличаются свойством неоднократного присваивания, однако во всех системах, где я их испытывал, получался один и тот же результат — увеличение i на 2. С другой стороны, оператор
i = 7, i++, i++;

в стандарте указан как пример defined behaviour — определенное поведение. Переменная i в данном случае равна 9. Таким образом, операция запятая может использоваться для «придания определенности» вычислениям. Другими операции, гарантирующими определенный порядок вычисления выражений являются логические операции И (||) и ИЛИ (&&).
Таким образом, многие вычисления необходимо явно проверять в той среде, с которой вы в данный момент работаете.


А>3. Означает ли это что приоритеты всегда и везде остаются постоянными(например при перегрузке операций) для всех операций и случай неопределенного поведения никак не связан с приоритетом, а поведение зависит только лишь от конкретной реализации компилятора?

Это да!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.