std::atomic::operator++,++(int),--,--(int)(3)

NAME
std::atomic::operator++,++(int),--,--(int) - std::atomic::operator++,++(int),--,--(int)

Synopsis
   T operator++() noexcept; (member only of atomic<Integral> template
   T operator++() volatile noexcept; (1) specialization)
                        (since C++11)
   T* operator++() noexcept; (member only of atomic<T*> template
   T* operator++() volatile noexcept; (1) specialization)
                        (since C++11)
   T operator++( int ) noexcept; (member only of atomic<Integral> template
   T operator++( int ) volatile (2) specialization)
   noexcept; (since C++11)
   T* operator++( int ) noexcept; (member only of atomic<T*> template
   T* operator++( int ) volatile (2) specialization)
   noexcept; (since C++11)
   T operator--() noexcept; (member only of atomic<Integral> template
   T operator--() volatile noexcept; (3) specialization)
                        (since C++11)
   T* operator--() noexcept; (member only of atomic<T*> template
   T* operator--() volatile noexcept; (3) specialization)
                        (since C++11)
   T operator--( int ) noexcept; (member only of atomic<Integral> template
   T operator--( int ) volatile (4) specialization)
   noexcept; (since C++11)
   T* operator--( int ) noexcept; (member only of atomic<T*> template
   T* operator--( int ) volatile (4) specialization)
   noexcept; (since C++11)
   Atomically increments or decrements the current value. The operation is
   read-modify-write operation.
   1) Performs atomic pre-increment. Equivalent to fetch_add(1)+1.
   2) Performs atomic post-increment. Equivalent to fetch_add(1).
   3) Performs atomic pre-decrement. Equivalent to fetch_sub(1)-1
   4) Performs atomic post-decrement. Equivalent to fetch_sub(1).
   For signed Integral types, arithmetic is defined to use two’s complement
   representation. There are no undefined results.
   For T* types, the result may be an undefined address, but the operations otherwise
   have no undefined behavior. The program is ill-formed if T is not an object type.
   The volatile-qualified versions are deprecated if (since C++20)
   std::atomic<T>::is_always_lock_free is false.

Parameters
   (none)

Return value
   1,3) The value of the atomic variable after the modification. Formally, the result
   of incrementing/decrementing the value immediately preceding the effects of this
   function in the modification order of *this.
   2,4) The value of the atomic variable before the modification. Formally, the value
   immediately preceding the effects of this function in the modification order of
   *this.

Notes
   Unlike most pre-increment and pre-decrement operators, the pre-increment and
   pre-decrement operators for atomic types do not return a reference to the modified
   object. They return a copy of the stored value instead.

Example
// Run this code
 #include <atomic>
 #include <chrono>
 #include <iomanip>
 #include <iostream>
 #include <mutex>
 #include <random>
 #include <thread>
 std::atomic<int> atomic_count{0};
 std::atomic<int> atomic_writes{0};
 constexpr int global_max_count{72};
 constexpr int writes_per_line{8};
 constexpr int max_delay{100};
 template<int Max> int random_value()
 {
     static std::uniform_int_distribution<int> distr{1, Max};
     static std::random_device engine;
     static std::mt19937 noise{engine()};
     static std::mutex rand_mutex;
     std::lock_guard μ{rand_mutex};
     return distr(noise);
 }
 int main()
 {
     auto work = [](const char id)
     {
         for (int count{}; (count = ++atomic_count) <= global_max_count;) {
             std::this_thread::sleep_for(
                 std::chrono::milliseconds(random_value<max_delay>()));
             bool new_line{false};
             if (++atomic_writes % writes_per_line == 0) {
                 new_line = true;
             }
             // print thread `id` and `count` value
             {
                 static std::mutex cout_mutex;
                 std::lock_guard m{cout_mutex};
                 std::cout << "[" << id << "] " << std::setw(3) << count << " │ "
                        << (new_line ? "\n" : "") << std::flush;
             }
         }
     };
     std::jthread j1(work, 'A'), j2(work, 'B'), j3(work, 'C'), j4(work, 'D');
 }

Possible output:
 [B] 3 │ [D] 1 │ [C] 2 │ [D] 6 │ [A] 4 │ [B] 5 │ [B] 10 │ [D] 8 │
 [C] 7 │ [A] 9 │ [A] 14 │ [B] 11 │ [D] 12 │ [C] 13 │ [A] 15 │ [C] 18 │
 [D] 17 │ [B] 16 │ [C] 20 │ [C] 23 │ [D] 21 │ [A] 19 │ [C] 24 │ [B] 22 │
 [A] 26 │ [C] 27 │ [D] 25 │ [C] 30 │ [B] 28 │ [D] 31 │ [A] 29 │ [C] 32 │
 [B] 33 │ [D] 34 │ [B] 37 │ [B] 39 │ [B] 40 │ [A] 35 │ [C] 36 │ [C] 43 │
 [D] 38 │ [A] 42 │ [B] 41 │ [A] 46 │ [B] 47 │ [C] 44 │ [A] 48 │ [D] 45 │
 [C] 50 │ [D] 52 │ [B] 49 │ [D] 54 │ [C] 53 │ [A] 51 │ [B] 55 │ [D] 56 │
 [D] 60 │ [A] 58 │ [C] 57 │ [D] 61 │ [C] 63 │ [B] 59 │ [D] 64 │ [C] 65 │
 [A] 62 │ [D] 67 │ [B] 66 │ [C] 68 │ [D] 70 │ [C] 72 │ [B] 71 │ [A] 69 │
  Defect reports
   The following behavior-changing defect reports were applied retroactively to
   previously published C++ standards.
     DR Applied to Behavior as published Correct behavior
   P0558R1 C++11 arithmetic permitted on pointers to cv void or made ill-formed
                      function

See also
              atomically adds the argument to the value stored in the atomic object and
   fetch_add obtains the value held previously
              (public member function)
              atomically subtracts the argument from the value stored in the atomic
   fetch_sub object and obtains the value held previously
              (public member function)
   operator+=
   operator-= adds, subtracts, or performs bitwise AND, OR, XOR with the atomic value
   operator&= (public member function)
   operator|=
   operator^=