Reputation: 5334
What are the Advantages/Drawbacks of these two ways of iterating through a container / which one do you prefer and why:
for (MyClass::iterator i = m.begin(), e = m.end() ; i != e ; i++)
{
// ...
}
or
for (MyClass::iterator i = m.begin() ; i != m.end() ; i++)
{
// ...
}
Subsidiary question: i++ or ++i? Why?
Upvotes: 1
Views: 3944
Reputation:
The C++ "for every element in container" loop is the most efficient where the context doesn't call for iterative logic.
for(Item& i : Container)
{
dosomething(i);
}
or
for(const Item& i : Container)
{
dosomething(i);
}
Upvotes: 2
Reputation:
The first one is faster because end()
isn't called on every iteration. And no, the optimizer can't easily cache that for you, because it doesn't know whether the size of the container has changed in this iteration (and hence the end moved). This also applies to a const container due to the aliasing problem.
i++
returns a copy of i, then increments. ++i
increments, then returns the incremented value. Hence, when you are discarding the return value, use ++i
because it needs to do less work (no copying). The optimizer is quite likely to fix an inlined i++
call so it's as fast as ++i
but don't rely on that.
Me? I use
for(int i = 0; i < m.size(); i++) {
// ... do something with m[i]
}
Because it's the shortest and most clear. Why int
and not MyClass::size_type
? Because it's simpler and I have never had to worry about the edge cases so far. Why i++
? Because for basic types it's always optimized into ++i
, and it's less confusing for coworkers. As a bonus, I can use i
as a numeric value as well. With an iterator, I'd have to keep a separate counter, or use std::distance
.
obecalp points out that this doesn't work with half of the standard containers, like list
and map
. Indeed those require using a proper iterator. Relatedly, you should always use an iterator
when writing generic code.
Upvotes: 1
Reputation: 414215
Boost.Foreach introduces a nice way:
#define foreach BOOST_FOREACH
// ...
Container<Item> container;
// ...
foreach (Item item, container) {
// do some stuff with the item
}
Upvotes: 0
Reputation: 1691
If the iterator is non-trivial (ie. not a pointer), ++i is definitely faster as it doesn't involves a copy to a temporary, which may or may not be optimized out.
The first form is a little faster but could be wrong if you erase or insert things in the loop.
For simple iteration over a container I use
#define foreach BOOST_FOREACH // in some header
foreach(MyType &element, any_container) {
// deal with element
}
most of the time for succinctness and clarity.
Upvotes: 5
Reputation: 44821
For normal stl iterators there's not a great deal of difference however if you collections are complex and asking for end is expensive then only asking for the end once may be faster.
Similarly for ++i vs i++, ++i can be a more expensive operation when the iterator is a complex class (rather than just a pointer as in the stl iterators) with i++ what's happening is that it's incrementing the iterator but returning a copy of the iterator in it's previous state. for ++i it's returning the iterator in it's current state so can just return a reference to itself.
It's usually best to only optimize your code when your profiler identifies that there's a problem there - it's better to keep the code as easily readable as possible.
Upvotes: 2
Reputation: 16249
I always do the second one actually, although I do worry sometimes if multiple calls to end slows things down at all. I was under the impression this would be optimised, but don't know that for sure.
And ++i definitely. It's never slower than i++, if anything it's faster.
Upvotes: 1
Reputation: 5523
Unless you have optimizations turned off, both are equivalent. As for i++ or ++i, ++i is more efficient because it does not involve a temporary value.
Upvotes: 3