HOWTO · C++

Pre-Increment VS Post-Increment Operators in C++

Learn how pre-increment (++x) and post-increment (x++) differ in C++ expression values, loops, and iterator usage, and how to avoid unsequenced access to a variable.

On this page

For a built-in arithmetic variable in C++, both ++x and x++ add one to x. The difference is the value produced by the expression: pre-increment produces the updated value, while post-increment produces the value from before the update. Choose based on which value the surrounding expression needs. For a user-defined type, overloaded increment operators follow their own definitions; by convention, they usually provide analogous prefix and postfix behavior.

Difference Between Pre-Increment and Post-Increment Operations in C++

For built-in arithmetic types, ++x updates x before producing the expression’s result. x++ produces the old value and completes the increment as part of the operation. In either case, the variable changes once. Overloaded operators may define different details, although they conventionally follow the same prefix/postfix distinction.

Run this example:

#include <iostream>

int main() {
    int value = 4;
    int previous = value++;
    int current = ++value;

    std::cout << previous << ' ' << current << ' ' << value << '\n';
}
4 6 6

previous receives the value from before the first increment; current receives the value after the second increment, which is also the final value of value.

The placement of an increment inside a loop body changes which value the body prints. In the first loop, i++ is the print expression: it prints the current value, then increments i. In the second, ++j runs before the print expression, so the body prints the updated value.

#include <iostream>

int main() {
    int i = 0;
    while (i < 5) {
        std::cout << i++ << '\n';
    }
    std::cout << "final i = " << i << '\n';
}
#include <iostream>

int main() {
    int j = 0;
    while (j < 5) {
        std::cout << ++j << '\n';
    }
    std::cout << "final j = " << j << '\n';
}

The first loop prints 0, 1, 2, 3, and 4, followed by final i = 5; the second prints 1, 2, 3, 4, and 5, followed by final j = 5. In both, the counter starts at 0, the body executes five times, and the final counter is 5. These examples increment in the body. By contrast, when the increment is in a for loop’s iteration expression, it runs after the body. If its result is discarded, replacing ++k with k++ leaves the sequence unchanged: both for (int k = 0; k < 5; ++k) and the version with k++ visit 0, 1, 2, 3, and 4, then finish with k equal to 5.

Avoid Modifying and Reading the Same Variable in One Expression

Do not combine an increment of a variable with another read of that variable in the same unsequenced expression. For example, k++ * k has undefined behavior in C++: the modification and the other read are unsequenced relative to each other. Its result cannot be predicted or used as a valid example output.

If the intended calculation is to multiply the old value by the next value, make the steps explicit and sequenced: initialize k, save it in old, increment k, and then calculate old * k.

The separate statements save the old value before incrementing k, then multiply the saved value by the updated value. Run this example:

#include <iostream>

int main() {
    int k = 10;
    int old = k;
    ++k;
    int product = old * k;

    std::cout << product << '\n';
}
110

How the Choice Changes With Iterators and User-Defined Types

The value distinction matters most when an increment is combined with another operation in the same expression. Dereferencing is the common case: *it++ means *(it++), so it reads the element the iterator currently points to and then advances the iterator. By contrast, *++it advances first and then reads the new element. Skipping or repeating an element during a traversal is often a prefix/postfix mix-up of exactly this kind, not a loop-condition mistake.

#include <iostream>
#include <vector>

int main() {
    std::vector<int> values{10, 20, 30};
    auto it = values.begin();

    std::cout << *it++ << '\n';
    std::cout << *it << '\n';
    std::cout << *++it << '\n';
}
10
20
30

The first line prints 10 and leaves the iterator pointing at 20; printing *it confirms the new position before *++it advances again and prints 30.

For a user-defined type, the two forms are two different functions. By convention, prefix increment is declared as operator++() and returns a reference to the updated object, while postfix increment is declared as operator++(int) — the int is a dummy marker, not a value the caller passes — saves a copy of the old state, increments through the prefix form, and returns that copy by value.

#include <iostream>

class Counter {
public:
    explicit Counter(int value) : value_(value) {}

    Counter& operator++() {
        ++value_;
        return *this;
    }

    Counter operator++(int) {
        Counter old = *this;
        ++(*this);
        return old;
    }

    int value() const { return value_; }

private:
    int value_;
};

int main() {
    Counter counter{5};
    Counter old = counter++;
    Counter& ref = ++counter;

    std::cout << old.value() << ' ' << counter.value() << ' '
              << ( &ref == &counter ) << '\n';
}
5 7 1

Here old keeps the starting value 5, the counter itself ends at 7 after both increments, and the final 1 confirms that prefix increment returned the counter itself, not a copy. The same distinction explains why the result of ++x still refers to x itself, while the result of x++ is a temporary copy of the old value.

This is also where the performance question becomes concrete. For a built-in integer whose result is discarded, compilers typically generate the same code for both forms, so preferring prefix there is a readability convention, not a speedup. The copy in postfix increment only costs something when copying is real work — a user-defined iterator or counter that copies state, or an overloaded operator that does more than add one. If a type defines only one of the two forms, the other form is simply unavailable; check the type’s declarations instead of assuming both exist.

When to Use Pre-Increment vs Post-Increment

Use post-increment when the expression needs the old value, as in int previous = value++;. Use pre-increment when the updated value is needed, or when the expression’s value is discarded, as it is in a loop’s iteration expression.

For iterators, pre-increment is a common convention when the old iterator value is not needed. A user-defined iterator’s overloaded operators follow their implementation, though they conventionally mirror the built-in prefix/postfix distinction. A postfix iterator operation may preserve and return a copy of the previous iterator; pre-increment can avoid that work for iterator types where the copy has a cost. This does not establish a measurable speed difference for a particular program: compiler optimization and the iterator implementation affect generated work.

Conclusion

Both forms increment the variable once. Pre-increment yields the updated value, and post-increment yields the previous value. Use the form that communicates which value the expression needs; for iterators, prefer pre-increment when the prior iterator value is unused, without assuming it guarantees a speedup.

FAQ

What is the main difference between pre-increment and post-increment?

For built-in arithmetic types, ++x updates first and yields the updated value. x++ yields the prior value and completes the increment. Overloaded operators follow their definitions, though they conventionally offer analogous prefix and postfix behavior.

Can I use either form in a loop?

Yes. In a for loop’s iteration expression, the result is usually discarded, so replacing ++i with i++ leaves that loop’s iteration sequence unchanged.

Which form is faster in C++?

There is no universal speed ranking for all expressions and types. Post-increment can involve a temporary copy for iterators or user-defined types; optimization may remove unnecessary work. Choose for the needed value and clear intent, and measure a real workload before making performance claims.

When is post-increment useful?

Use it when the expression needs the value from before the increment, such as assigning that value to another variable.

Do pre-increment and post-increment behave the same in every language?

No. Operators with similar spelling can have language-specific rules. Check the semantics of the language you are using; the explanations here are for C++.