Здравствуйте, Аноним, Вы писали:
А>Объясните почему при перегрузке операции постфиксного инкремента ++(и/или =) А>получается что вначале выполняется оператор ++ а только потом = в выражении
У Вас неверно передана семантика постфиксного инкремента. Вот с этой версией Ваши тесты пошли?
aa operator ++(const int ab)
{
aa temp(*this);
ii++;
return temp;
}
Здравствуйте, Аноним, Вы писали:
А>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. Означает ли это что приоритеты всегда и везде остаются постоянными(например при перегрузке операций) для всех операций и случай неопределенного поведения никак не связан с приоритетом, а поведение зависит только лишь от конкретной реализации компилятора?
Это да!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, romam, Вы писали:
АШ>>У Вас неверно передана семантика постфиксного инкремента. Вот с этой версией Ваши тесты пошли? АШ>>
АШ>>aa operator ++(const int ab)
АШ>>{
АШ>> aa temp(*this);
АШ>> ii++;
АШ>> return temp;
АШ>>}
АШ>>
R>С этой версией выражение R>x=x++; R>для инта приводит к увеличению х на еденицу, а для перегруженного ++ — нет. Имхо это можно объяснить только тем, что у интового ++ низкий приоритет, выполняется сначала R>х=х; R> потом — R>x++; R>А у перегруженного ++ — высокий.
Неправильно. Выражение x=x++ для int приводит не к увеличению x на 1, а к неопределенному поведению, поскольку в этом случае происходит одновременная модификация скалярного объекта более одного раза.
R>Проверялось на компиляторе под Linux (g++) и в MSVS 6.0
Ну и что? На других компиляторах или с другими ключами компиляции ты можешь получить иные результаты.
Объясните почему при перегрузке операции постфиксного инкремента ++(и/или =)
получается что вначале выполняется оператор ++ а только потом = в выражении
p = d++;// -> p = (d++)
снизу показан пример
class aa
{
int i;
public:
aa(){ i=0;}
aa(int _i){ i=_i;}
aa& operator ++(const int ab)
{
i++;
return *this;
}
aa operator =(aa x)
{
i = x.i;
return *this;
}
};
в итоге имеем что
p.i = 11
d.i = 11
a = 10
b = 11
Вопросы следующие:
1.При перегрузке операций приоритет меняется?(мне кажется не должно)
2 Если приоритет не меняется то почему получаются разные результаты(можно ли это объяснить на уровне синnаксиса — то есть то то выполняется раньше этого потому то потому то — или это разработчики VC так захотели)
3.Как правильно реализовать оператор ++ чтобы он мог работал также как и для типа int и вообще возможно ли это сделать?
4.Что считать выражением? Могут ли в выражение входить вызовы функций и что раньше вызывается вызовы функций или постфиксный инкремент
Пример:
int func(int &a, int b)
{
return a+b;
}
int i = 0;
int x = 0;
x = func(i,i++)+i++;
В данном случае получается что первый постфиксный инкремент ++ идет раньше вызова функции func
Возможно я неправильно понимаю что значит выражение.
Re[2]: приоритеты перегрженных операций
От:
Аноним
Дата:
06.07.04 17:53
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:
АШ>Здравствуйте, Аноним, Вы писали:
А>>Объясните почему при перегрузке операции постфиксного инкремента ++(и/или =) А>>получается что вначале выполняется оператор ++ а только потом = в выражении
АШ>У Вас неверно передана семантика постфиксного инкремента. Вот с этой версией Ваши тесты пошли?
АШ>
АШ>aa operator ++(const int ab)
АШ>{
АШ> aa temp(*this);
АШ> ii++;
АШ> return temp;
АШ>}
АШ>
АШ>У Вас неверно передана семантика постфиксного инкремента. Вот с этой версией Ваши тесты пошли?
АШ>
АШ>aa operator ++(const int ab)
АШ>{
АШ> aa temp(*this);
АШ> ii++;
АШ> return temp;
АШ>}
АШ>
С этой версией выражение
x=x++;
для инта приводит к увеличению х на еденицу, а для перегруженного ++ — нет. Имхо это можно объяснить только тем, что у интового ++ низкий приоритет, выполняется сначала
х=х;
потом —
x++;
А у перегруженного ++ — высокий.
Проверялось на компиляторе под Linux (g++) и в MSVS 6.0
Re[4]: приоритеты перегрженных операций
От:
Аноним
Дата:
07.07.04 04:40
Оценка:
Здравствуйте, folk, Вы писали:
F>Здравствуйте, romam, Вы писали:
АШ>>>У Вас неверно передана семантика постфиксного инкремента. Вот с этой версией Ваши тесты пошли? АШ>>>
АШ>>>aa operator ++(const int ab)
АШ>>>{
АШ>>> aa temp(*this);
АШ>>> ii++;
АШ>>> return temp;
АШ>>>}
АШ>>>
R>>С этой версией выражение R>>x=x++; R>>для инта приводит к увеличению х на еденицу, а для перегруженного ++ — нет. Имхо это можно объяснить только тем, что у интового ++ низкий приоритет, выполняется сначала R>>х=х; R>> потом — R>>x++; R>>А у перегруженного ++ — высокий.
F>Неправильно. Выражение x=x++ для int приводит не к увеличению x на 1, а к неопределенному поведению, поскольку в этом случае происходит одновременная модификация скалярного объекта более одного раза.
R>>Проверялось на компиляторе под Linux (g++) и в MSVS 6.0
F>Ну и что? На других компиляторах или с другими ключами компиляции ты можешь получить иные результаты.
1.Правильно ли я понял что неопределенное поведение возникает только при модификации переменной в выражении больше одного раза?
2.Означает ли это что если я не модифицирую переменную в выражении больше 1 раза то я могу быть уверен что выражение будет работать одинаково на всех компиляторах?
3. Означает ли это что приоритеты всегда и везде остаются постоянными(например при перегрузке операций) для всех операций и случай неопределенного поведения никак не связан с приоритетом а поведение зависит только лишь от конкретной реализации компилятора?
А>3. Означает ли это что приоритеты всегда и везде остаются постоянными(например при перегрузке операций) для всех операций и случай неопределенного поведения никак не связан с приоритетом а поведение зависит только лишь от конкретной реализации компилятора?
Приоритеты остаются, но в данном случае это не играет никакой роли. И вообще, приоритет и порядок вычисления — вещи разные. Например в выражении
a * b++ + c++
различие приоритетов сложения и умножения означает лишь то, что c++ будет прибавлено к результату умножения, а не наоборот. Однако инкремент как b, так и c может быть выполнен как до, так и после сложения и умножения. Но даже если инкремент c++ будет выполнен до сложения, в выражении все равно будет использоваться значение c до инкремента. Опять же, не из за приоритетов, а просто потому, что это постинкремент.