In your for loop, you have three separate expressions, each evaluated at different times.
The first one, int i = 0 is evaluated before the first iteration.
The second one i <= 10 is evaluated before each iteration.
The third one i++ or ++i is evaluated after each iteration.
Since the second and third expressions are evaluated separately, and the value of i++ or ++i itself is never used (only its side effect), there is no difference in apparent behaviour in this case.
On the other hands, statements like: int j = i++; and int k = ++i; do yield different results. j will get the value of i
before incrementation, and k will get the value of i
after incrementation.
The reason why people advise to always use pre-incrementation (++i) is simple. When you use post-increment, the old value of i must be saved, then i is incremented, then the old value is returned. For basic types, and with today''s compilers, it doesn''t matter much, since the order of operations can simply be changed (use the value and only when you''re done, increment it).
But for user-defined types, such optimization cannot easily be done. You end up defining your operation like so:
Foo operator++(Foo& foo, int) // Postincrement (dummy ''int'' parameter){ Foo temp = foo; // Make local copy of the old value. ++foo.bar; // Manipulate foo somehow. return temp; // Return temp by value.}Foo& operator++(Foo& foo) // Preincrement{ ++foo.bar; // Manipulate foo somehow. return foo; // Return foo by reference.}
Depending on how complex Foo is, in particular the presence of a copy constructor, there may be no way to optimize the copying away from the post-increment function even if you declare the function inline, which leads to performance penalties. If you are not going to use the return value itself, there is therefore no point in using postincrement.
Now, you''ll ask me, why would you ever use a user-defined type in a for loop or similar? Well, all standard C++ containers (vector, deque, list...) provide iterator types for the specific purpose of walking (iterating) through their elements with such a loop. Incrementing the iterator means "move to the next element", which is done differently depending on the container: you don''t find the next element in the same way for a vector (contiguous storage, the next element *is* next in memory) or a list (linked list, has to follow a ''next'' pointer)...
So, iterator types need to define their own increment functions, which are not necessarily trivial. I think you''ll agree with me there is no point in calling a version that does extra work (back the old iterator up), if you''re not drawing any benefit from it.
Conclusion: use preincrement everywhere unless you have specific reasons not to. It takes the same number of keystrokes, is just as readable, will always give you at least as good performance as postincrement. And you''ll get used to it in no time.
“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.” — Brian W. Kernighan (C programming language co-inventor)
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan