Theory and Reality

One thing which I am pretty religious about is the placement of ++ and — in an expression. You have two options for where it can go. If it goes before the operand, it’s a pre-increment/decrement. If it goes after the operand, it’s a post-increment/decrement. They have different semantics, and so there are correctness issues with their placement. But what I want to talk about are the cases where there are not correctness issues, and what should happen.

A good example of what I am talking about is with for loops. We’ve all written loops like this at some point:

for (int i = 0; i < 10; i++) {}

In this case, the increment operator doesn’t really matter whether it happens before i is evaluated or after because the value of i is ignored in that part of the expression. So what’s the “right” answer?

For about as long as I can remember, I’ve pushed people to pre-increment instead of post-increment. The reason being is that it’s more efficient. When you pre-increment, you evaluate i to get its value, add one to the value, then store it back into i and the resulting value can be used in the expression. When you post increment, you evaluate i to get its value, store the value off somewhere, add one to the value, then store it back into i and the value you stored off is the resulting value to be used in the expression. In more concrete terms (pseudo-assembly):

# ++i
load i into register 1
increment register 1
store register one into i
// register 1 contains the result

# i++
load i into register 1
load i into register 2
increment register 1
store register 1 into i
// register 2 contains the result

You might think that this has no practical benefit, but think about overloaded operator ++ and how it would behave. For instance, with iterator objects. In the case of iterator++, you have to create an extra copy of the iterator to return to the caller, but with ++iterator you do not. If copying iterators were expensive, then iterator++ would be more expensive on every pass through the loop because you could be making a copy of the iterator to return to the expression, and immediately throwing it away because it’s not used. So this is why I always suggest to pre-increment when the result doesn’t matter.

That’s the theory, anyway. But the reality is: it doesn’t matter. In a release build of your application, any compiler worth its salt is going to optimize the increment exactly the same, regardless of whether it’s a pre- or post-increment. This is because the optimizer can see that the value is ignored, and so it doesn’t matter which gets called.

This is a salient message to always write the clearest code you can, right up until you need to optimize. Compiler optimizers have gotten pretty good in recent history, and so oftentimes your micro-optimizations don’t make a difference. So write clear, maintainable code, and worry about the optimizations for when you’ve proven they’re beneficial.

Of course, I’ll still pre-increment because it states my intent better. ;-)

This entry was posted in C/C++ and tagged , . Bookmark the permalink.

Leave a Reply

Your email address will not be published.