C++ Pre-Increment VS Post-Increment
Introduction
When I was programming C in college, I wrote i++
or ++i
interchangeably, especially in a for
loop, because I know their performance and consequence are exactly the same. However, “good” C++ programmers almost never write i++
.
In this blog post, I would like to discuss the difference between i++
or ++i
and the best practice for performance in C++.
C++ VS ++C
There is a difference between the consequence of i++
or ++i
if their return values are being assigned or copied to variables. In this article, we are only interested in talking about i++
or ++i
when their return values are not being assigned or copied to variables.
C
In C, the pre-increment and post-increment ++
are defined for built-in primitive types. When a compiler sees the code containing i++
, such as
1 | for (int i; i < 10; i++) |
Because the return value of i++
, the value of i
before increment, was never assigned, the copy and return operation might just be casted away by the compiler, and i++
becomes exactly the same as ++i
.
Notice that there is no operator overloading in C, and the pre-increment and post-increment ++
are only defined for built-in primitive types. Therefore, there is no story about the performance of the pre-increment and post-increment of user defined types in C.
C++
In C++, if the variable is of built-in primitive types, the pre-increment and post-increment ++
can also be optimized by the compiler similarly as in C. However, because C++ supports operator overloading, therefore the pre-increment and post-increment ++
can also be defined for user defined types.
For example, we have the following Int
class and we have defined the pre-increment and post-increment ++
operators for it. A more complicated non-primitive type which supports ++
in C++ STL is iterator.
1 |
|
Because the pre-increment and post-increment ++
are inlined, i.e., the definition and the declaration are together, the compiler would see the definition of the post-increment ++
when generating the code for i++
, therefore, it is possible that the compiler could optimize away the copy of the object in the post-increment member function for the i++
code.
However, in this case, GCC did not optimize the copy of the object away in the post-increment member function for the i++
code, even if GCC could.
1 | $ g++ int.cpp -o int -std=c++14 |
If the pre-increment and post-increment ++
were are not inlined, it is impossible for the compiler to optimize away the copy of the object in the post increment function.
For example, if the Int
class was declared in a header int.h
file and defined in another file int.cpp
, the compiler cannot optimize the post-increment ++
by just looking at the header declaration.
1 |
|
1 |
|
The member functions are not inlined in this case either, even if the declaration and the definition are in the same header file int.h
.
1 |
|
Only by adding the inline
keyword would the compiler inline
the member functions. In this case, the compiler has a chance to optimize away the copy of the object in the post increment function.
1 |
|
Conclusions
The performance of i++
would never be better than the performance of ++i
in C++ if their return values are never being assigned or copied to variables. In this scenario, we should only write ++i
in C++. Only write i++
when we want to assign or copy the value of i
before increment in C++.
References
C++ Pre-Increment VS Post-Increment
https://leimao.github.io/blog/CPP-Pre-Increment-VS-Post-Increment/