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

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

Войти
Регистрация
Восстановить пароль
 
popelyuk
8 / 8 / 1
Регистрация: 04.12.2012
Сообщений: 130
#1

Почему операторы инкремента действуют по разному для стандартных и нестандартных типов? - C++

19.01.2013, 23:17. Просмотров 430. Ответов 4
Метки нет (Все метки)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class my {
    int i;
public:
    my(int in) :i(in) {}
    operator int () {
        return i;
    }
    int operator=(int in) {
        i=in; return i;
    }
    int operator ++() {
        i=i+7;
        return i;
    }
    int operator ++(int) {
        int tmp=i;
        i=i+7;
        return tmp;
    }
    int operator --() {
        i=i-7;
        return i;
    }
    int operator --(int) {
        int tmp=i;
        i=i-7;
        return tmp;
    }
};
 
 
int main() {
    my m=100; int s=100;
    int res_s=s++ + s++;    // почему здесь res = 200
    int res_m=m++ + m++;  // а зесь нет??
     
    std::cout<<"res_s="<<res_s<<std::endl;
    std::cout<<"res_m="<<res_m<<std::endl;
    return 0;
}
Вот что получаем на выходе:
Почему операторы инкремента действуют по разному для стандартных и нестандартных типов?
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
19.01.2013, 23:17
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Почему операторы инкремента действуют по разному для стандартных и нестандартных типов? (C++):

Почему не происходит автоматическое преобразование стандартных типов? - C++
Имеется следующий код : int a = 10; cout&lt;&lt;a/100&lt;&lt;endl; Вариант из явным преобразованием работает чудесно :

Специализация шаблона для стандартных типов - C++
Пишу динамическую структуру данных (не суть важно какую, допустим для простоты стек). Она работает с объектами типа Box, которые: 1....

Операторы инкремента и декремента - C++
Создайте в классе Circle префиксный и постфиксный операторы инкремента и декремента, воздействующие только на член-данное радиус itsRadius.

Преобразования стандартных типов - C++
Добрый день, можете пожалуйста кинуть какой-нибудь FAQ по критическим преобразованиям стандартных типов в языке Си(++). Например, ...

Переобъявление стандартных типов C++ - C++
Не давно в голову пришла идея переобъявить стандартные типы через union, это может дать возможность обращения к байтам или битам числа, вот...

Автоматическое преобразование стандартных типов - C++
Если моя функция LOG принимает qString* можно ли сделать так чтобы автоматически вызывалась конструирование временного объекта и он...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
lemegeton
2924 / 1353 / 135
Регистрация: 29.11.2010
Сообщений: 2,725
19.01.2013, 23:27 #2
Это undefined behaviour, поскольку последовательность выполнения операций (не приоритет, а именно последовательность) не определена.
Не буду вдаваться в детали, но компилятор определяет в какой момент выполнения производится инкремент/декремент операнда, стандартом это не определено. Поэтому результат и странен.
0
OhMyGodSoLong
~ Эврика! ~
1243 / 992 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
19.01.2013, 23:33 #3
Потому что для пользовательских типов перегруженные операторы — это вызовы функций, а для встроенных их родные операторы — нет.

Есть такая вещь — sequence point (точка следования). Это точка в коде, до которой должны выполниться все побочные эффекты (все присваивания, которые по каким-то причинам отложили, например; в частности, присваивания, неявно возникающие при инкрементах). Точками следования, в частности, являются вызовы функций (для внутренних побочных эффектов и вычислений в аргументах), а также полные операторы (грубо, точки с запятой).

Так вот, в вашей строке 34 всего одна точка следования — аккурат на точке с запятой. Компилятор может извращаться со значением переменной как хочет, но после точки с запятой она должна быть увеличена на два. Не факт, правда, что увеличение будет происходить в два этапа. Ваш компилятор, например, сначала подставил старые значения, а потом вписал увеличение на два. А чей-то другой может вычислять по шагам: запомнить старое, увеличить на один, прибавить увеличенное на один к старому, увеличить ещё раз на единицу. В результате выведет 201 и будет прав. Это, что называется, неопределённое поведение.

А вот в строке 35 точек следования три: по одной на каждом инкременте, так как m++ + m++ это на самом деле operator++(m) + operator++(m), ну и одна в конце выражения. Поэтому здесь компилятор просто обязан выполнять инкременты последовательно: сначала выдать старое значение, потом увеличить его на 7, потом прибавить к старому значению увеличенное на 7 и снова увеличить на 7, выдавая в итоге 207.
2
popelyuk
8 / 8 / 1
Регистрация: 04.12.2012
Сообщений: 130
19.01.2013, 23:33  [ТС] #4
Цитата Сообщение от lemegeton Посмотреть сообщение
Это undefined behaviour, поскольку последовательность выполнения операций (не приоритет, а именно последовательность) не определена.
Не буду вдаваться в детали, но компилятор определяет в какой момент выполнения производится инкремент/декремент операнда, стандартом это не определено. Поэтому результат и странен.
а как же вот эта табличка, тут оператор инкремента/дикримента в самом конце после равно и прочих:
Почему операторы инкремента действуют по разному для стандартных и нестандартных типов?
0
popelyuk
8 / 8 / 1
Регистрация: 04.12.2012
Сообщений: 130
19.01.2013, 23:36  [ТС] #5
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
Потому что для пользовательских типов перегруженные операторы — это вызовы функций, а для встроенных их родные операторы — нет.

Есть такая вещь — sequence point (точка следования). Это точка в коде, до которой должны выполниться все побочные эффекты (все присваивания, которые по каким-то причинам отложили, например; в частности, присваивания, неявно возникающие при инкрементах). Точками следования, в частности, являются вызовы функций (для внутренних побочных эффектов и вычислений в аргументах), а также полные операторы (грубо, точки с запятой).

Так вот, в вашей строке 34 всего одна точка следования — аккурат на точке с запятой. Компилятор может извращаться со значением переменной как хочет, но после точки с запятой она должна быть увеличена на два. Не факт, правда, что увеличение будет происходить в два этапа. Ваш компилятор, например, сначала подставил старые значения, а потом вписал увеличение на два. А чей-то другой может вычислять по шагам: запомнить старое, увеличить на один, прибавить увеличенное на один к старому, увеличить ещё раз на единицу. В результате выведет 201 и будет прав. Это, что называется, неопределённое поведение.

А вот в строке 35 точек следования три: по одной на каждом инкременте, так как m++ + m++ это на самом деле operator++(m) + operator++(m), ну и одна в конце выражения. Поэтому здесь компилятор просто обязан выполнять инкременты последовательно: сначала выдать старое значение, потом увеличить его на 7, потом прибавить к старому значению увеличенное на 7 и снова увеличить на 7, выдавая в итоге 207.
Спасибо, очень хороший ответ
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
19.01.2013, 23:36
Привет! Вот еще темы с ответами:

Почему при выводе указателя получаем для char - значение по адресу, а для других типов - адрес - C++
Есть следующий код. Результат работы этой программы представлен на рисунке. Почему при выводе указателя для char возвращается значение, а...

Операторы преобразования типов - C++
Допустим у меня есть класс A. И я определяю для этого класса следующие конструкторы преобразования: A::operator char * () const; ...

операторы преобразования типов - C++
что но не пойму сам принцип работы опреаторов преобразования.. вот к примеру: class Cat{ public: Cat(){itsAge=192;} ...

Для чего необходимо переопределение стандартных типов? - C (СИ)
Добрый вечер, часто сталкиваюсь с переопределением имен стандартных типов особенно в С для микроконтроллеров, вроде такого: ...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
19.01.2013, 23:36
Ответ Создать тему
Опции темы

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