приоритеты перегрженных операций
От: Аноним  
Дата: 06.07.04 15:18
Оценка:
Объясните почему при перегрузке операции постфиксного инкремента ++(и/или =)
получается что вначале выполняется оператор ++ а только потом = в выражении

 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
42:       x = func(i,i++) + i++;
0040D566   mov         eax,dword ptr [ebp-4]
0040D569   mov         dword ptr [ebp-0Ch],eax
0040D56C   mov         ecx,dword ptr [ebp-0Ch]
0040D56F   push        ecx
0040D570   lea         edx,[ebp-4]
0040D573   push        edx
0040D574   mov         eax,dword ptr [ebp-4]
0040D577   add         eax,1
0040D57A   mov         dword ptr [ebp-4],eax
0040D57D   call        @ILT+65(func) (00401046)
0040D582   add         esp,8
0040D585   add         eax,dword ptr [ebp-4]
0040D588   mov         dword ptr [ebp-8],eax
0040D58B   mov         ecx,dword ptr [ebp-4]
0040D58E   add         ecx,1
0040D591   mov         dword ptr [ebp-4],ecx


В тоге имеем

x = 2
i = 2


Возможно я неправильно понимаю что значит выражение.
Re: приоритеты перегрженных операций
От: Анатолий Широков СССР  
Дата: 06.07.04 15:26
Оценка: 2 (2) +1
Здравствуйте, Аноним, Вы писали:

А>Объясните почему при перегрузке операции постфиксного инкремента ++(и/или =)

А>получается что вначале выполняется оператор ++ а только потом = в выражении

У Вас неверно передана семантика постфиксного инкремента. Вот с этой версией Ваши тесты пошли?

aa operator ++(const int ab)
{
    aa temp(*this);
    ii++;  
    return temp;
}
Re[2]: приоритеты перегрженных операций
От: Аноним  
Дата: 06.07.04 17:53
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

АШ>Здравствуйте, Аноним, Вы писали:


А>>Объясните почему при перегрузке операции постфиксного инкремента ++(и/или =)

А>>получается что вначале выполняется оператор ++ а только потом = в выражении

АШ>У Вас неверно передана семантика постфиксного инкремента. Вот с этой версией Ваши тесты пошли?


АШ>
АШ>aa operator ++(const int ab)
АШ>{
АШ>    aa temp(*this);
АШ>    ii++;  
АШ>    return temp;
АШ>}
АШ>


угу работают
Re[2]: приоритеты перегрженных операций
От: romam  
Дата: 07.07.04 03:06
Оценка:
АШ>У Вас неверно передана семантика постфиксного инкремента. Вот с этой версией Ваши тесты пошли?

АШ>
АШ>aa operator ++(const int ab)
АШ>{
АШ>    aa temp(*this);
АШ>    ii++;  
АШ>    return temp;
АШ>}
АШ>


С этой версией выражение
x=x++;
для инта приводит к увеличению х на еденицу, а для перегруженного ++ — нет. Имхо это можно объяснить только тем, что у интового ++ низкий приоритет, выполняется сначала
х=х;
потом —
x++;
А у перегруженного ++ — высокий.
Проверялось на компиляторе под Linux (g++) и в MSVS 6.0
Re[3]: приоритеты перегрженных операций
От: folk Россия  
Дата: 07.07.04 04:08
Оценка: +1
Здравствуйте, 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


Ну и что? На других компиляторах или с другими ключами компиляции ты можешь получить иные результаты.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
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. Означает ли это что приоритеты всегда и везде остаются постоянными(например при перегрузке операций) для всех операций и случай неопределенного поведения никак не связан с приоритетом а поведение зависит только лишь от конкретной реализации компилятора?
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. Означает ли это что приоритеты всегда и везде остаются постоянными(например при перегрузке операций) для всех операций и случай неопределенного поведения никак не связан с приоритетом, а поведение зависит только лишь от конкретной реализации компилятора?

Это да!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[5]: приоритеты перегрженных операций
От: SWW Россия  
Дата: 07.07.04 05:45
Оценка:
А>3. Означает ли это что приоритеты всегда и везде остаются постоянными(например при перегрузке операций) для всех операций и случай неопределенного поведения никак не связан с приоритетом а поведение зависит только лишь от конкретной реализации компилятора?

Приоритеты остаются, но в данном случае это не играет никакой роли. И вообще, приоритет и порядок вычисления — вещи разные. Например в выражении
a * b++ + c++

различие приоритетов сложения и умножения означает лишь то, что c++ будет прибавлено к результату умножения, а не наоборот. Однако инкремент как b, так и c может быть выполнен как до, так и после сложения и умножения. Но даже если инкремент c++ будет выполнен до сложения, в выражении все равно будет использоваться значение c до инкремента. Опять же, не из за приоритетов, а просто потому, что это постинкремент.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.