In for
-loops, people will tell you to always increment using ++c
instead of c++
. Why exactly is this? And will it affect your program in any way?
The observable difference between ++c
and c++
is that the former evaluates to c+1
, and the latter to c
:
int main() { int c = 1; cout << ++c << endl; // 2 cout << c++ << endl; // still 2 cout << c << endl; // 3 }
First of all, to get that question out of the way: This does not mean that the first alternative will increment c
at the beginning of the iteration. Both alternatives increment c
at the end of each iteration:
int main() { for (int c = 0; c < 1; c++) { cout << c << endl; // 0 } for (int c = 0; c < 1; ++c) { cout << c << endl; // still 0 } }
So what then, is the point? Speed is.
Consider how the ++c
operator would be implemented. No one will ever use the old value of c
, so the implementer is free to increment c
and then provide a reference to the freshly updated object. Now consider c++
. Here, the implementer needs to provide a reference to the not-updated object, but still increment it. A common way to do this is to make an unmodified copy of c
, increment the original c
, and then return the copy. See the following example:
struct C { int _i; C(int i = 0) : _i(i){} C& operator++() { _i++; return *this; } C operator++(int) { C tmp(_i); _i++; return tmp; } }; ostream& operator<< (ostream& os, const C& c) { os << c._i; return os; } int main () { C c; cout << c << endl; //0 cout << c++ << endl; //0 cout << ++c << endl; //2 }
As you can see, this introduces unnecessary overhead, especially for complex classes.
But what about built in types? For these, there will typically be no overhead using c++
, but if you get into the habit of always using ++c
, you won’t forget when you are incrementing more complex classes.
And as @tfheen points out, “[cases like the above example will be optimized away by] any compiler less than 30 years old.”, so this advice is probably not that relevant anymore. But now at least you know the reasoning when you see it.
Compiler will definitely optimize the temporary away when it detects that post-increment is unnecessary. However, in debug builds, there are often no optimization. I’ve seen enough times where debug build runs too slow to be debugged. I would still use pre-increment whenever possible.
Nice article btw.
Good point about debug builds, I didn’t think about that. Thanks for your comment!
Ha ha … The c is s much better name!