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?

7
  • 1
    Funny, I would say that the first is more "traditional", being the way you would do that in C... Commented Mar 23, 2012 at 2:58
  • Duplicate of this question Commented Mar 23, 2012 at 2:58
  • 4
    Think about iterating over a list, or a map, or pretty much anything other than vectors and arrays. Commented Mar 23, 2012 at 2: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. Commented Mar 23, 2012 at 3:00
  • 2
    The "textbook" method would be: for(vector::iterator it=someVector.begin(), end=someVector.end(); it!=end; ++it) Commented Mar 23, 2012 at 3:03

5 Answers 5

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.

Sign up to request clarification or add additional context in comments.

3 Comments

I see that you prefix the non-member begin() and end() function with namespace qualifier. Doesn't this inhibit argument dependant lookup and, by the way, remove the utility they provide as free function?
@authchir: Fixed before you commented.
@Niklas: As mentioned in my answer, these work with plain ol' arrays.
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.

5 Comments

The second option wouldn't work with most containers either, since it requires operator< for iterators.
@BenVoigt: Sorry, I don't understand your comment. Could you clarify please?
@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.
@Greg: At the time I commented, the question code contained it < someVector.end(). But most iterators only have equality comparison, not ordering.
@BenVoigt: Ah, I didn't even notice that and it had already been changed to != by the time I looked again.
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.

Comments

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.

Comments

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.