Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Перегрузка оператора пост-инкремента, Приоритет перегруженных операторов 
V
    Опции темы
wrathchildtoo
Дата 21.7.2009, 11:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 6.4.2009

Репутация: нет
Всего: нет



В общем, заметил такую особенность, что при перегрузке оператора постфиксного инкремента, если не предпринимать особых мер, приоритет его меняется на префиксную форму (становится как у префиксной формы). Декремента это касается в равной степени. 
Если же использовать некоторую уловку в виде возвращения временного значения, то такой перегруженный оператор работает корректно только в определенных случаях.

Листинг проги с перегрузкой инкремента без возврата временного значения:
Код
//postfix.cpp

#include<iostream>

using namespace std;

class Integer
{
    friend ostream &operator<<(ostream &, const Integer &); // перегрузка оператора "поместить в поток"

private:
    int a;

public:
    Integer(int = 0);
    Integer operator++(); //перегрузка префиксного инкремента
    Integer operator++(int); //перегрузка постфиксного инкремента
};

// перегрузка оператора "поместить в поток"
ostream &operator<<(ostream &output, const Integer &num)
{
    output << num.a;

    return output;
}

//конструктор преобразования
Integer::Integer(int num)
{
    a = num;
}

//перегрузка префиксного инкремента
Integer Integer::operator++()
{
    ++a;

    return *this;
}

//перегрузка постфиксного инкремента, не использующего временного значения
Integer Integer::operator++(int)
{
    a++;
    
    return *this;
}


int main()
{
    Integer a = 5;
    int b = 5;

    cout << "  a = " << a << endl;
    cout << "++a = " << ++a << endl;
    cout << "  a = " << a << endl;
    cout << "a++ = " << a++ << endl; //сначала производится инкремент, а потом выводится на экран
    cout << "  a = " << a << endl << endl;

    cout << "  b = " << b << endl;
    cout << "++b = " << ++b << endl;
    cout << "  b = " << b << endl;
    cout << "b++ = " << b++ << endl; //сначала выводится на экран, а затем - инкремент
    cout << "  b = " << b << endl;

    return 0;
}

Операторная функция перегрузки пост-инкремента с возвращаемым временным значением:
Код
Integer Integer::operator++(int)
{
    Integer temp = *this;
    a++;
    
    return temp;
}

Если вызывать эту функцию из выражения:
Код

cout << "a++ = " << a++ << endl;
проблем никаких не возникает, но если вызывать её в более сложном выражении, например в таком:
Код

cout << << "a = " << a << "  a++ = " << a++ << endl;

то уже при выводе на экран значения "а" будет выводится инкрементированное значение.

Вот, собственно, и возникает вопрос: существуют ли какие-нибудь более универсальные приемы при перегрузке постфиксных функций?

Это сообщение отредактировал(а) wrathchildtoo - 21.7.2009, 11:09
PM MAIL   Вверх
zim22
Дата 21.7.2009, 11:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 29
Всего: 69



Цитата(wrathchildtoo @  21.7.2009,  11:08 Найти цитируемый пост)
существуют ли какие-нибудь более универсальные приемы при перегрузке постфиксных функций?

мне кажется проблема возникает из-за непонимания приоритета операторов.
сдвиг влево (<<) расположен в таблице приоритетов ниже, чем постфиксный инкремент (lvalue++).
это значит, что он будет выполняться после того, как инкремент отработает.
***
вот пример, иллюстрирующий "проблему" smile
не смотря на то, что "hello" написано левее, чем вызов функции, функция - отрабатывает первой. опять же из за приоритета.
Код

struct S {
  operator int() {  std::cout << "I am first!\n"; return 5; }
};

int main()
{
  std::cout << "hello" << S() << std::endl;
    return 0;
}


Это сообщение отредактировал(а) zim22 - 21.7.2009, 11:22


--------------------
PM MAIL   Вверх
wrathchildtoo
Дата 21.7.2009, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 6.4.2009

Репутация: нет
Всего: нет



Цитата(zim22 @  21.7.2009,  11:16 Найти цитируемый пост)
сдвиг влево (<<) расположен в таблице приоритетов ниже, чем постфиксный инкремент (lvalue++)

Нет, это не правда!
В подтверждение этого, я привел пример со встроенным типом int. Для него пост-инкремент работает как надо.
PM MAIL   Вверх
zim22
Дата 21.7.2009, 11:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 29
Всего: 69



Цитата(wrathchildtoo @  21.7.2009,  11:23 Найти цитируемый пост)
Нет, это не правда!

в таком случае да поможет вам Бог smile
Цитата(wrathchildtoo @  21.7.2009,  11:23 Найти цитируемый пост)
 я привел пример со встроенным типом int

в какой строке?


--------------------
PM MAIL   Вверх
wrathchildtoo
Дата 21.7.2009, 11:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 6.4.2009

Репутация: нет
Всего: нет



Цитата(zim22 @  21.7.2009,  11:27 Найти цитируемый пост)
в какой строке?

Код
    int b = 5;

    cout << "  b = " << b << endl;
    cout << "++b = " << ++b << endl;
    cout << "  b = " << b << endl;
    cout << "b++ = " << b++ << endl; //сначала выводится на экран, а затем - инкремент
    cout << "  b = " << b << endl;


Это сообщение отредактировал(а) wrathchildtoo - 21.7.2009, 11:30
PM MAIL   Вверх
zim22
Дата 21.7.2009, 11:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 29
Всего: 69



Цитата(wrathchildtoo @  21.7.2009,  11:30 Найти цитируемый пост)
//сначала выводится на экран, а затем - инкремент

ассемблерный листинг другого мнения. обратите внимание на строку со знаками восклицания
Код

cout << "b++ = " << b++; //сначала выводится на экран, а затем - инкремент
012E1559  mov         eax,dword ptr [b] 
012E155C  mov         dword ptr [ebp-0D0h],eax 
012E1562  mov         ecx,dword ptr [b] 
012E1565  add         ecx,1 ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
012E1568  mov         dword ptr [b],ecx 
012E156B  mov         esi,esp 
012E156D  mov         edx,dword ptr [ebp-0D0h] 
012E1573  push        edx  
012E1574  push        offset string "b++ = " (12E7800h) 
012E1579  mov         eax,dword ptr [__imp_std::cout (12EA304h)] 
012E157E  push        eax  
012E157F  call        std::operator<<<std::char_traits<char> > (12E115Eh) 
012E1584  add         esp,8 
012E1587  mov         ecx,eax 
012E1589  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (12EA300h)] 
012E158F  cmp         esi,esp 
012E1591  call        @ILT+425(__RTC_CheckEsp) (12E11AEh) 



--------------------
PM MAIL   Вверх
wrathchildtoo
Дата 21.7.2009, 11:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 6.4.2009

Репутация: нет
Всего: нет



zim22, ну я же не выдумываю:
Код
#include<iostream>
using namespace std;

int main()
{
    int b = 5;

    cout << "b++ = " << b++ << endl;
    cout << "b = " << b << endl;

    return 0;
}

вот что выводится на экран:
Цитата
b++ = 5
b = 6
Press any key to continue . . .


PM MAIL   Вверх
mes
Дата 21.7.2009, 12:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(wrathchildtoo @  21.7.2009,  10:08 Найти цитируемый пост)
то уже при выводе на экран значения "а" будет выводится инкрементированное значение.

приоритет тут не при чем.


--------------------
PM MAIL WWW   Вверх
wrathchildtoo
Дата 21.7.2009, 12:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 6.4.2009

Репутация: нет
Всего: нет



Приношу свои извенения. Со встроенными типами, похоже, постфикс работает тоже через временное значение:
Код

#include<iostream>
using namespace std;

int main()
{
    int b = 5;

    cout << "b = " << b << "; b++ = " << b++ << endl;
    cout << "b = " << b << endl;

    return 0;
}

Цитата
b = 6; b++ = 5
b = 6
Press any key to continue . . .

Тему можно закрывать

Это сообщение отредактировал(а) wrathchildtoo - 21.7.2009, 12:00
PM MAIL   Вверх
xvr
Дата 21.7.2009, 12:04 (ссылка) |    (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Вот это
Код

//перегрузка постфиксного инкремента, не использующего временного значения
Integer Integer::operator++(int)
{
    a++;
    
    return *this;
}
в принципе неверно. Семантика реализации вашего 'постфиксного инкремента' на самом деле соотвествует префиксной форме, т.к. возвращается объект ПОСЛЕ инкремента, а не ДО (как должно быть)
Вариант
Код

Integer Integer::operator++(int)
{
    Integer temp = *this;
    a++;
    
    return temp;
}
правильный.
Что касается 
Код

cout << "a = " << a << "  a++ = " << a++ << endl;
то здесь UB (модификация и использование переменной не разделены sequence point)




Это сообщение отредактировал(а) xvr - 21.7.2009, 12:09
PM MAIL   Вверх
wrathchildtoo
Дата 21.7.2009, 12:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 6.4.2009

Репутация: нет
Всего: нет



Всем спасибо.
PM MAIL   Вверх
wrathchildtoo
Дата 24.7.2009, 10:28 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 6.4.2009

Репутация: нет
Всего: нет



Вот что по этому поводу говорит сам создатель C++ Бьярне Страуступ:
Цитата

What's the value of i++ + i++?
It's undefined. Basically, in C and C++, if you read a variable twice in an expression where you also write it, the result is undefined. Don't do that. Another example is: 
    v[i] = i++;
Related example: 
    f(v[i],i++);
Here, the result is undefined because the order of evaluation of function arguments are undefined. 

Having the order of evaluation undefined is claimed to yield better performing code. Compilers could warn about such examples, which are typically subtle bugs (or potential subtle bugs). I'm disappointed that after decades, most compilers still don't warn, leaving that job to specialized, separate, and underused tools.

http://www.research.att.com/~bs/bs_faq2.ht...valuation-order
PM MAIL   Вверх
UnrealMan
Дата 24.7.2009, 17:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 722
Регистрация: 30.3.2006

Репутация: 5
Всего: 32



Цитата(xvr @ 21.7.2009,  12:04)
Что касается 
Код

cout << "a = " << a << "  a++ = " << a++ << endl;
то здесь UB (модификация и использование переменной не разделены sequence point)

Что ты тут подразумеваешь под UB, и при чём тут sequence point?

Это сообщение отредактировал(а) UnrealMan - 24.7.2009, 18:00
PM MAIL   Вверх
xvr
Дата 24.7.2009, 18:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(UnrealMan @ 24.7.2009,  17:58)
Цитата(xvr @  21.7.2009,  12:04 Найти цитируемый пост)
то здесь UB (модификация и использование переменной не разделены sequence point)

Что ты тут подразумеваешь под UB, 

Вот это
Код

cout << "a = " << a << "  a++ = " << a++ << endl;
раскрывется в нечто такое
Код

operator << (
 operator << (
  operator << (
   operator << (
    operator << (cout,"a = "),
    a),
   " a++ = "),
  a++),
 endl);
Как видим имеет место быть вычисление параметров фунций (operator <<) a и a++. Порядок вычисления этих параметров не определен, равно как и момент финального инкремента a. То, что вызовы самих operator<< упорядоченны роли не играет - компилятор имеет право вычислить параметры для этих вызовов в любом порядке. Так что чему будет равно a в самом внутреннем вызове неизвестно - это и есть UB
Цитата

и при чём тут sequence point?
Если бы она здесь была, и разделяла a и a++, то UB не было бы.

Похоже я не прав - sequence point тут вроде есть - вызов функции (operator<<). Так что UB тут нет

Цитата

When calling a function (whether or not the function is inline), there is a sequence point after the evaluation of all
function arguments (if any) which takes place before execution of any expressions or statements in the function body.


Это сообщение отредактировал(а) xvr - 24.7.2009, 18:21
PM MAIL   Вверх
UnrealMan
Дата 24.7.2009, 18:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 722
Регистрация: 30.3.2006

Репутация: 5
Всего: 32



Цитата(xvr @  24.7.2009,  18:09 Найти цитируемый пост)
Так что чему будет равно a в самом внутреннем вызове неизвестно - это и есть UB

Ты так и не сказал, что такое UB. Похоже сокращение какое-то, только непонятно, чего именно.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0703 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.