views:

730

answers:

6

My workmate claims that for object types preincrement is more efficient than post increment

e.g.

std::vector<std::string> vec;

... insert a whole bunch of strings into vec ...

// iterate over and do stuff with vec.  Is this more efficient than the next 
// loop?
std::vector<std::string>::iterator it;
for (it = vec.begin(); it != vec.end(); ++it){

}

// iterate over and do stuff with vec.  Is this less efficient than the previous loop?
std::vector<std::string>::iterator it;
for (it = vec.begin(); it != vec.end(); it++){

}
+5  A: 

For primitive types, I used to do this. It used to get me about 10% boost in many programs on Visual Studio back in 1998/1999. Shortly after that, they fixed their optimizer. The post increment operator created a variable on the stack, copied the value, incremented the source, and then removed the variable from the stack. Once the optimizers detected it was not being used, the benefit went away.

Most people did not stop coding that way. :) It took me a few years.

For objects, I am not sure how that would work. I assume a copy operator would be required for a true implementation of post increment. It would have to make a copy and use the copy for the operations, and increment the source.

Jacob

TheJacobTaylor
+19  A: 

Postincrement must return the value the iterator had BEFORE it was incrementing; so, that previous value needs to be copied somewhere before altering it with the increment proper, so it's available to return. The extra work may be a little or a lot, but it certainly can't be less than zero, compared to a preincrement, which can simply perform the incrementing and then return the just-altered value -- no copying // saving // etc necessary.

So, unless you specifically MUST have postincrement (because you're using the "value before increment" in some way), you should always use preincrement instead.

Alex Martelli
There really isn't any reason for the standard iterators to be slower; isn't the compiler allowed to assume stuff in std:: behaves as the standard specifies, and thus do the same optimization it does for built-in types?
derobert
derobert: Yes, if it can. Not all iterator types are simple enough to do that kind of optimization. If the object is large "enough" you can have a slowdown. It arguably will almost never matter, but one uses this idiom in tight loops, where it really can.
quark
Kind of a popular folklore-esque question. Nice to hear some real details on it.
Brandon Pelfrey
+4  A: 

The default increment operators will look like this:

class X
{
    X operator++(int)  // Post increment
    {
        X  tmp(*this);
        this->operator++(); // Call pre-increment on this.
        return tmp;
    }
    X& operator++(int)  // Pre increment
    {
        // Do operation for increment.
        return *this;
    }
};

Notice the Post-increment is defined in terms of the Pre-increment. So Post-increment does the same work plus some extra. Usually this is construct a copy and then return the copy via a copy (Note the Pre-increment can return itself by reference but the Post-increment can not).

Martin York
+1  A: 

Seriously, unless you're actually having performance problems due to calling post-increment instead of pre-increment THE PERFORMANCE DIFFERENCE WILL ONLY MATTER IN VERY RARE CIRCUMSTANCES.


Update

For instance, if your software is a climate simulation, and operator++ causes the simulation to move forward a step (that is ++simulation gives you the next step in the simulation, while simulation++ makes a copy of the current step in the simulation, advances the simulation, and then hands you the copy) then performance will be an issue.

More realistically, in a comment, the original questioner mentions that we're discussing an embedded project with (apparently) real time requirements. In that case you need to actually look at your specific implementation. I seriously doubt that you'll have noticeable slowdowns iterating through a std::vector with post-increment instead of pre-increment, although I haven't benchmarked any STL implementation on this matter.


Don't pick one over the other for performance reasons. Pick one over the other for clarity/maintenance reasons. Personally I default to pre-increment because I generally don't give a damn what the value was before incrementing.

If your brain blows up when you see ++i instead of i++ it may be time to consider going into a different line of work.

Max Lybbert
Correct. But you should prefer pre-increment. The reason being that when somebody changes an underlying type in the system you don't need to go back and verify all your post-increments are efficient or not. So for maintainability you should prefer pre-increment.
Martin York
I don't have performance problems yet, but it pays to think performance in the systems I'm working on. The software is operating in the telcoms sector handling thousands of calls per second. I thought I'd simply ask whether there is a performance difference and obviously there is.
Matt H
Very Correct. But the question wanted to know which one is more efficient only.
n002213f
In any reasonable implementation, pre-increment will be at least as fast as post-increment. If there's a difference, you should use pre-increment. If there isn't, you may as well use pre-increment.
David Thornley
A: 

I know this is like "hangar-flying" in aviation. I'm sure it is purely academic, and you know if it makes a hoot of difference you need to be re-thinking your code.

Example: I got a comment on some answer I gave to some question about performance tuning, and it went like this:

Person: I tried your method of randomly halting and looking at the call stack. I did it several times, but it makes no sense. All the time, it is deep in some iterator-increment code. What good is that?

Me: That's great! It means nearly all your time is going into incrementing iterators. Just look higher up the stack and see where it is coming from. Replace that with simple integer-increment, and you'll get a massive speedup.

Of course, you might prefer the prettiness of iterator-incrementing, but it's easy enough to find out if it's costing you much performance.

Mike Dunlavey