Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/7: Рейтинг темы: голосов - 7, средняя оценка - 5.00
 Аватар для popelyuk
8 / 8 / 2
Регистрация: 04.12.2012
Сообщений: 130

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

19.01.2013, 23:17. Показов 1545. Ответов 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
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
19.01.2013, 23:17
Ответы с готовыми решениями:

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

Почему z-index отрицательный и положительный по-разному действуют на псевдоэлементы?
Здравствуйте! Бился сегодня над решением создать через ::before декоративный элемент за текстом, так чтобы текст был на первом плане. ...

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

4
 Аватар для lemegeton
4903 / 2696 / 921
Регистрация: 29.11.2010
Сообщений: 5,783
19.01.2013, 23:27
Это undefined behaviour, поскольку последовательность выполнения операций (не приоритет, а именно последовательность) не определена.
Не буду вдаваться в детали, но компилятор определяет в какой момент выполнения производится инкремент/декремент операнда, стандартом это не определено. Поэтому результат и странен.
0
~ Эврика! ~
 Аватар для OhMyGodSoLong
1258 / 1007 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
19.01.2013, 23:33
Потому что для пользовательских типов перегруженные операторы — это вызовы функций, а для встроенных их родные операторы — нет.

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

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

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

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

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

А вот в строке 35 точек следования три: по одной на каждом инкременте, так как m++ + m++ это на самом деле operator++(m) + operator++(m), ну и одна в конце выражения. Поэтому здесь компилятор просто обязан выполнять инкременты последовательно: сначала выдать старое значение, потом увеличить его на 7, потом прибавить к старому значению увеличенное на 7 и снова увеличить на 7, выдавая в итоге 207.
Спасибо, очень хороший ответ
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
19.01.2013, 23:36
Помогаю со студенческими работами здесь

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

Операторы инкремента и декремента
в роди понимаю как работает,начинаю проверять вручную и не получается. помогите разобраться как считает эта программа. static void...

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

Определение и использование функций для обработки стандартных типов данных
Заданы три числа. Отрицательные числа заменить абсолютными значениям, нулевые значения – единицами, положительные – увеличить в два раза.

Объявление обобщённого типа (Generic) для стандартных целочисленных типов
Здравствуйте. Есть класс для вычисления факториала: public class Factorial { long _digit; public...


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru