Spec-Zone.ru › C++

Операторы инкремента/декремента

Операторы инкремента/декремента увеличивают или уменьшают значение объекта.

Название оператора Синтаксис Можно перегрузить Примеры прототипов (для classT)
Внутри определения класса Вне определения класса
префиксный инкремент ++a Да T& T::operator++(); T& operator++(T& a);
префиксный декремент --a Да T& T::operator--(); T& operator--(T& a);
постфиксный инкремент a++ Да T T::operator++(int); T operator++(T& a, int);
постфиксный декремент a-- Да T T::operator--(int); T operator--(T& a, int);
Примечания
  • Префиксные версии встроенных операторов возвращают ссылки, а постфиксные версии — значения. Типичные перегрузки, определяемые пользователем, следуют этому шаблону, благодаря чему пользовательские операторы можно использовать так же, как встроенные. Однако при перегрузке пользовательского оператора в качестве возвращаемого типа можно использовать любой тип (в том числе void).
  • Параметр int — фиктивный параметр, который используется для различения префиксных и постфиксных версий операторов. При вызове пользовательского постфиксного оператора значение, передаваемое этому параметру, всегда равно нулю, хотя его можно изменить, вызвав оператор с помощью синтаксиса вызова функции (например, a.operator++(2) или operator++(a, 2)).

Префиксные операторы

Выражения префиксного инкремента и декремента имеют вид

++ выражение
-- выражение
1) префиксный инкремент
2) префиксный декремент

Встроенные префиксные операторы

1) Выражение ++x эквивалентно x += 1, за следующими исключениями:
  • Если тип выражения — bool (возможно, с квалификатором volatile), значению выражения присваивается true. Такой инкремент считается устаревшим.
(до C++17)
  • Если тип выражения — bool (возможно, с cv-квалификаторами), программа некорректна.
(начиная с C++17)
  • Если тип выражения имеет квалификатор volatile, инкремент считается устаревшим.
(начиная с C++20)
2) Выражение --x эквивалентно x -= 1, за следующими исключениями:
  • Если тип выражения — bool (возможно, с cv-квалификаторами), программа некорректна.
  • Если тип выражения имеет квалификатор volatile, декремент считается устаревшим.
(начиная с C++20)

Перегрузки

При разрешении перегрузки для пользовательских операторов в разрешении перегрузки участвуют следующие сигнатуры функций для каждого арифметического типа A, который может иметь квалификатор volatile, кроме bool, а также для каждого указателя P, который может иметь квалификатор volatile и указывает на тип объекта, который может иметь cv-квалификаторы:

A& operator++(A&)
bool& operator++(bool&)
(устарело)(до C++17)
P& operator++(P&)
A& operator--(A&)
P& operator--(P&)

Постфиксные операторы

Выражения постфиксного инкремента и декремента имеют вид

выражение ++
выражение --
1) постфиксный инкремент
2) постфиксный декремент

Встроенные постфиксные операторы

Результат постфиксного инкремента или декремента — значение, полученное применением преобразования lvalue в rvalue к выражению (до изменения). Тип результата — версия типа выражения без cv-квалификаторов.

Если выражение не является модифицируемым lvalue арифметического типа, отличного от bool (возможно, с cv-квалификаторами)(начиная с C++17), или указателем на полный тип объекта, программа некорректна.

Если тип выражения имеет квалификатор volatile, инкремент или декремент считается устаревшим.

(начиная с C++20)
1) Значение выражения изменяется так, как если бы оно было операндом префиксного оператора ++.
2) Значение выражения изменяется так, как если бы оно было операндом префиксного оператора --.

Вычисление значения постфиксного инкремента или декремента упорядочено перед изменением выражения. Относительно вызова функции с неопределённым порядком следования операция постфиксного инкремента или декремента является одним вычислением.

Перегрузки

При разрешении перегрузки для пользовательских операторов в разрешении перегрузки участвуют следующие сигнатуры функций для каждого арифметического типа A, который может иметь квалификатор volatile, кроме bool, а также для каждого указателя P, который может иметь квалификатор volatile и указывает на тип объекта, который может иметь cv-квалификаторы:

A operator++(A&, int)
bool operator++(bool&, int)
(устарело)(до C++17)
P operator++(P&, int)
A operator--(A&, int)
P operator--(P&, int)

Пример

#include <iostream>

int main()
{
    int n1 = 1;
    int n2 = ++n1;
    int n3 = ++ ++n1;
    int n4 = n1++;
//  int n5 = n1++ ++;   // error
//  int n6 = n1 + ++n1; // undefined behavior
    std::cout << "n1 = " << n1 << '\n'
              << "n2 = " << n2 << '\n'
              << "n3 = " << n3 << '\n'
              << "n4 = " << n4 << '\n';
}

Вывод:

n1 = 5
n2 = 2
n3 = 4
n4 = 4

Примечания

Из-за побочных эффектов встроенные операторы инкремента и декремента следует использовать с осторожностью, чтобы избежать неопределённого поведения вследствие нарушения правил упорядочивания.

Поскольку при постфиксном инкременте и декременте создаётся временная копия объекта, в контекстах, где возвращаемое значение не используется, префиксные операторы инкремента и декремента обычно эффективнее.

Стандартная библиотека

Операторы инкремента и декремента перегружены для многих типов стандартной библиотеки. В частности, у каждого LegacyIterator перегружен operator++, а у каждого LegacyBidirectionalIterator перегружен operator--, даже если эти операторы ничего не делают для конкретного итератора.

перегрузки для арифметических типов
operator++operator++(int)operator--operator--(int)
увеличивает или уменьшает атомарное значение на единицу
(открытая функция-член std::atomic<T>)
operator++operator++(int)operator--operator--(int)
увеличивает или уменьшает количество тактов
(открытая функция-член std::chrono::duration<Rep,Period>)
перегрузки для типов итераторов
operator++operator++(int)
продвигает итератор
(открытая функция-член std::raw_storage_iterator<OutputIt,T>)
operator++operator++(int)operator+=operator+operator--operator--(int)operator-=operator-
продвигает или перемещает назад reverse_iterator
(открытая функция-член std::reverse_iterator<Iter>)
operator++operator++(int)operator+=operator+operator--operator--(int)operator-=operator-
продвигает или перемещает назад move_iterator
(открытая функция-член std::move_iterator<Iter>)
operator++operator++(int)
ничего не делает
(открытая функция-член std::front_insert_iterator<Container>)
operator++operator++(int)
ничего не делает
(открытая функция-член std::back_insert_iterator<Container>)
operator++operator++(int)
ничего не делает
(открытая функция-член std::insert_iterator<Container>)
operator++operator++(int)
продвигает итератор
(открытая функция-член std::istream_iterator<T,CharT,Traits,Distance>)
operator++operator++(int)
ничего не делает
(открытая функция-член std::ostream_iterator<T,CharT,Traits>)
operator++operator++(int)
продвигает итератор
(открытая функция-член std::istreambuf_iterator<CharT,Traits>)
operator++operator++(int)
ничего не делает
(открытая функция-член std::ostreambuf_iterator<CharT,Traits>)
operator++operator++(int)
продвигает итератор к следующему совпадению
(открытая функция-член std::regex_iterator<BidirIt,CharT,Traits>)
operator++operator++(int)
продвигает итератор к следующему подсовпадению
(открытая функция-член std::regex_token_iterator<BidirIt,CharT,Traits>)

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены ретроспективно к ранее опубликованным стандартам C++.

DR Применяется к Опубликованное поведение Корректное поведение
CWG 2855 C++98 обычные арифметические преобразования применялись для встроенных префиксных инкремента и
декремента, но не применялись для соответствующих постфиксных операторов[1]
также применяются
CWG 2901 C++98 преобразования lvalue в rvalue не применялись
для встроенных постфиксных инкремента и декремента
применяются
  1. Префиксный ++x эквивалентен x += 1, а последний применим к обычным арифметическим преобразованиям (то есть даёт общий тип для decltype(x) и int). Однако эффект постфиксного x++ — это просто «прибавление единицы к x»; бинарный оператор отсутствует, поэтому обычные арифметические преобразования не выполняются.

См. также

Приоритет операторов

Перегрузка операторов

Основные операторы
Присваивание Инкремент,
декремент
Арифметические Логические Сравнения Доступ к
членам
Другие
a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b
++a
--a
a++
a--
+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b
!a
a && b
a || b
a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b
a[...]
*a
&a
a->b
a.b
a->*b
a.*b
вызов функции

a(...)
запятая

a, b
условный оператор

a ? b : c
Специальные операторы

static_cast преобразует один тип в другой связанный тип
dynamic_cast выполняет преобразование в иерархиях наследования
const_cast добавляет или удаляет cv-квалификаторы
reinterpret_cast преобразует тип в несвязанный тип
Приведение в стиле C преобразует один тип в другой посредством сочетания static_cast, const_cast и reinterpret_cast
new создаёт объекты с динамической длительностью хранения
delete уничтожает объекты, ранее созданные выражением new, и освобождает занятую ими область памяти
sizeof запрашивает размер типа
sizeof... запрашивает размер пакета (начиная с C++11)
typeid запрашивает информацию о типе
noexcept проверяет, может ли выражение выбросить исключение (начиная с C++11)
alignof запрашивает требования к выравниванию типа (начиная с C++11)
^^ создаёт значение отражения на основе грамматической конструкции (начиная с C++26)

Документация по C для Операторы инкремента/декремента

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/operator_incdec

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API