tags:

views:

606

answers:

7

Someone told me that I can write

for (iterator it = somecontainer.begin(); it != somecontainer.end(); ++it)

instead of

for (iterator it = somecontainer.begin(); it != somecontainer.end(); it++)

...since the latter one has the cost of an extra unused temporary variable. Is this optimization useful for modern compiler? Do I need to consider this optimization when writing code?

+29  A: 

It's a good habit to get into, since iterators may be arbitrarily complex. For vector::iterator or int indexes, no, it won't make a difference.

The compiler can never eliminate (elide) the copy because copy elision only eliminates intermediate temporaries, not unused ones. For lightweight objects including most iterators, the compiler can optimize out the code implementing the copy. However, it isn't always obvious when it can't. For example, post-incrementing istream_iterator<string> is guaranteed to copy the last string object read. On a non-reference-counted string implementation, that will allocate, copy, and immediately free memory. The issue is even more likely to apply to heavier, non-iterator classes supporting post-increment.

There is certainly no disadvantage. It seems to have become the predominant style over the past decade or two.

Potatoswatter
+1 -- Not only iterators, but any type with an `operator++`.
Billy ONeal
+4  A: 

No. (Stylistically I prefer it, because my native language is English which is mostly a verb-precedes-noun language, and so "increment it" reads more easily than "it increment". But that's style and subjective.)

However, unless you're changing somecontainer's contents in your loop, you might consider grabbing the return value of somecontainer.end() into a temporary variable. What you're doing there will actually call the function on every loop.

T.J. Crowder
@Bertrand: Indeed!
T.J. Crowder
Not really. `somecontainer.end()` is probably just going to be an inlined function, which probably contains at worst a pointer addition. Before extracting temporaries like this one should consider using things like `std::for_each` instead.
Billy ONeal
@Billy: We have no idea what `somecontainer.end()` is, how complex it is, or how expensive it is, and shouldn't code as though we do. But I will say that this entire question and most of the answers (including mine) look a lot like premature optimization. ;-)
T.J. Crowder
@Billy: Completely agree about using "each" style constructs where they exist.
T.J. Crowder
@T.J. `end()` is guaranteed to be O(1) for a compliant container, and pretty much any reasonable non-compliant container will also implement it in just a few instructions, which can be eliminated in a comparably small loop by lack of potential aliasing. The real issue is termination conditions which are more complex than a call to `end`, e.g. `it != find( string.begin(), string.end(), '|' )`.
Potatoswatter
+5  A: 

Yes, that's conceptually the right thing to do. Do you care if it's i++ or ++i? No, you don't. Which one is better? The second one is better since it's potentially faster. So you choose the second (pre-increment).

In typical cases there will be no difference in emitted code, but the iterators can have whatever implementation. You can't control it and you can't control whether the compiler will emit good code. What you can control is how you conveys your intent. You don't need the post-increment here.

sharptooth
I believe the OP already knows that. He knows it's potentially faster, what he's asking is it *typically* faster, because any reasonable compiler is going to ignore this for builtin types.
Billy ONeal
@Billy ONeal: This will depend on how the iterator is implemented inside and what the compiler thinks of it. The OP can't control that. What he can control is how he conveys his intent.
sharptooth
@sharptooth: I'm not disagreeing with you or saying you're wrong. That just doesn't look like the question asked though.
Billy ONeal
@Billy ONeal: I don't argue with you either. I guess the key here is noone knows how the iterator is implemented inside, so in most cases there will be no difference, but not always.
sharptooth
+3  A: 

It depends on the type to which you're applying operator++. If you are talking about a user defined type, that's going to involve copying the entire UDT, which can be very expensive.

However, if you are talking about a builtin type, then there's likely no difference at all.

It's probably good to get in the habit of using preincrement where possible even when postincrement is fine, simply to be in the habit and to give your code a consistent look. You should be leaning on the compiler to optimize some things for you, but there's no reason to make it's job harder than it has to be for no reason whatsoever.

Billy ONeal
+4  A: 

I don't normally consider the prefix ++ an optimization. It's just what I write by default, because it might be faster, it's just as easy to write, and there's no downside.

But I doubt it's worth going back and changing existing code to use the prefix version.

jalf
+3  A: 

Consider how post-increment is typically implemented in a user-defined type:

MyIterator operator++(int) {
    MyIterator retval(*this);
    ++*this;
    return retval;
}

So we have two questions: can my compiler optimise this in cases where the return value is unused, and will my compiler optimise this in cases where the return value is unused?

As for "can it?", there certainly are cases where it can't. If the code isn't inlined, we're out of luck. If the copy constructor of MyIterator has observable side effects then we're out of luck - copy constructor elision allows return values and copies of temporaries to be constructed in place, so at least the value might only be copied once. But it doesn't allow return values not to be constructed at all. Depending on your compiler, memory allocation might well be an observable side-effect.

Of course iterators usually are intended to be inlined, and iterators usually are lightweight and won't take any effort to copy. As long as we're OK on these two counts, I think we're in business - the compiler can inline the code, spot that retval is unused and that its creation is side-effect free, and remove it. This just leaves a pre-increment.

As for "will it?" - try it on your compiler. I can't be bothered, because I always use pre-increment where the two are equivalent ;-)

For "do I need to consider this optimization when writing code?", I would say not as such, but that premature pessimization is as bad a habit as premature optimization. Just because one is (at best) a waste of time does not mean that the other is noble - don't go out of your way to make your code slower just because you can. If someone genuinely prefers to see i++ in a loop then it's fairly unlikely ever to make their code slower, so they can optimise for aesthetics if they must. Personally I'd prefer that people improve their taste...

Steve Jessop
+1  A: 

It will actually make a difference in unoptimized code, which is to say debug builds.

Rob K
And to add something to that, it's one less thing for the optimizer to worry about when you are using it.
Rob K