3

This may seem like an odd question but I was talking to a friend today who was ranting about today's C++ programmers and how they just don't do things quite right. He said his main pet peeve was the abuse of iterating, in code like this:

for(int i = 0; i<((int) someVector.size()); ++i){
    //Something here
}

instead of the more traditional

vector::iterator i;
for(i = someVector.begin(); i!=someVector.end(); ++i){
    //Something here
}

While I understand both methods, is there any particular reason why the second is superior to the first? Is it performance? Or some other factor?

Thanks in advance.

daniel gratzer
  • 52,833
  • 11
  • 94
  • 134
  • 1
    Funny, I would say that the first is more "traditional", being the way you would do that in C... – Greg Hewgill Mar 23 '12 at 02:58
  • Duplicate of [this question](http://stackoverflow.com/questions/776624/whats-faster-iterating-an-stl-vector-with-vectoriterator-or-with-at) – xdumaine Mar 23 '12 at 02:58
  • 4
    Think about iterating over a list, or a map, or pretty much anything other than vectors and arrays. – Pablo Mar 23 '12 at 02:59
  • Iterators win because 1) they work with standard algorithms 2) most standard containers aren't indexable, only `vector<>` and `deque<>`, but all support iterators. – ildjarn Mar 23 '12 at 03:00
  • Both are traditional. C programmers use both ptr arithmetics and subscripts. However, compilers often treat subscripts better with respect to optimizations, because those loops are easier to analyze, unroll, etc. –  Mar 23 '12 at 03:00
  • 2
    The "textbook" method would be: `for(vector::iterator it=someVector.begin(), end=someVector.end(); it!=end; ++it)` – David Schwartz Mar 23 '12 at 03:03
  • Don't use `<` with iterators. Use `!=` – Martin York Mar 23 '12 at 03:07

5 Answers5

4

Neither one of those is good style.

The first has a useless and dangerous cast.

The second allows the iteration variable to leak outside the loop's scope, and doesn't use an equality test, and uses a post-increment on an iterator, which makes a useless copy.

Better is:

using std::begin, std::end;
for( auto it = begin(container), end_it = end(container); it != end_it; ++it )

This works with any STL container, arrays, and any container you provide with begin and end helper functions.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
1

For a vector, there is little difference between the two. However, if you wanted to iterate over a data structure such as a set, that doesn't have random access at all, then the second option using iterators would be the only sensible choice.

The C++ standard library goes to great effort to make the "iterator" interface as consistent as possible over many different types of containers.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • The second option wouldn't work with most containers either, since it requires `operator<` for iterators. – Ben Voigt Mar 23 '12 at 03:01
  • @BenVoigt: Sorry, I don't understand your comment. Could you clarify please? – Greg Hewgill Mar 23 '12 at 03:08
  • @GregHewgill: `<` is only defined for Randome Iterators i.e It would work only if the container was `std::deque` or `std::vector`, So better option is to use `!=` which is defined for all iterator types. – Alok Save Mar 23 '12 at 03:09
  • @Greg: At the time I commented, the question code contained `it < someVector.end()`. But most iterators only have equality comparison, not ordering. – Ben Voigt Mar 23 '12 at 03:10
  • @BenVoigt: Ah, I didn't even notice that and it had already been changed to `!=` by the time I looked again. – Greg Hewgill Mar 23 '12 at 03:12
0

In some data structures it could be inefficient to calculate the size. Depending on how much the optimizer can do, this might actually end up calling the size() method for every iteration of the loop. When you use the second code passage, you don't rely on calling a method to calculate the size, when all you really want is to know whether you've reached the end.

For instance, consider a linked list. Unless the linked list is designed to keep a count internally, you have to iterate through the whole list to find the size. Also, for data structures, there is no way to use an index to get a value out. In this case, you've got to use the proper iterator methods.

Eric Andres
  • 3,417
  • 2
  • 24
  • 40
0

There are generally no real performance gains in using an iterator. Possibly less. However, they have a few potential advantages over the "C method" of iterating:

1) It is potentially easier to abstract the container through an iterator. Since we deal with a pointer each iteration, if the container type needs to change and accessing an element by index changes in form (or isn't even possible because random access isn't possible), an iterator could save some tedious editing.

2) You can avoid using size() each iteration. Although you could precalculate it once, it's still nicer to avoid it altogether.

3) You essentially deal with a pointer to each element in the container you're iterating through. This is nicer (well, at least to me it is) and possibly more compact than an index.

Alex Z
  • 2,500
  • 2
  • 19
  • 23
0

First and foremost, I'd note that most code shouldn't have explicit loops at all. If you're going to operate on a collection, you should use an algorithm. If one of the standard algorithms won't do the job, you should usually still implement what you need as an algorithm, and then apply that algorithm where needed (but if you start paying attention, you'll probably be surprised at how often the standard algorithms will work).

If you really do need to write an explicit loop, consider using a range-based loop instead:

for (auto i : someVector)
    // ... 

Most of the time, however, this should be in the implementation of an algorithm.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111