Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I've read a couple of articles (example) that consider the classic

for (int ...... size() .... i++) loop bad practice when iterating through for example vectors in stl. Instead the recommended why is to use vector iterators, i.e. begin, end, etc.

Why is that?

share|improve this question
    
Who said it's a bad practise? –  m0nhawk Jan 1 '13 at 15:25
    
For example here: cprogramming.com/tutorial/stl/iterators.html –  user357320 Jan 1 '13 at 15:27
    
I guess you have a performance penalty accessing certain collections through an index. Scanning the same collections (e.g. a linked list) with an iterator should be much faster. –  Giorgio Jan 1 '13 at 15:28
1  
@Giorgio: That's definitely depends on a collection, that being used. –  m0nhawk Jan 1 '13 at 15:37
    
@m0nhawk: That's what I meant by "certain": not all collections might suffer from this problem. Some are designed for random access, other for sequential access. –  Giorgio Jan 1 '13 at 15:41
show 1 more comment

4 Answers

up vote 6 down vote accepted

If you know you're operating on a std::vector, and that's never going to change, there's nothing fundamentally wrong with that form of for loop - it's well understood, easy to read, and the compiler will usually do a good job of eliminating the potential cost of calling size() on every loop.

But using a for loop with iterators is more generic. It doesn't require that your container have a size() operator at all, and doesn't require that the container have index-based accessors at all (let alone efficient ones). So your code will be more generic if you go that route.

Other things to consider these days:

  • The range-base for loop: compact syntax, very few requirements on the container type.
  • Algorithms like for_each/find/fill/... combined with lambdas if the body of the loop lends itself to it for more functional-style C++.
share|improve this answer
    
For improved clarity, perhaps you can mention linked list and associative containers (set, map) as examples. –  rwong Jan 1 '13 at 23:44
add comment

I wouldn't say it's a bad practice, I would say that using an iterator as the better practice.

Why? Because it's more explicit. With a normal loop you aren't necessarily using each element, you could be doing a related, but not directly connected operation. For instance a group chartering program might book X number of tickets because it has a group of size X, where the ticket assignment happens in a later stage.

Using the iterator says that you are going over the collection and doing something with each element. It conveys the intent of the program better.

share|improve this answer
add comment

It depends upon the implementation of the collection. Some collections do not have a fast and ready way to determine the number of elements they contain. For these collections, calling size() may require a complete iteration through the collection just to tell you how many there are. Such collections may not have an easy mechanism for random access either.

For example, a collection of "lines in a text file" would require parsing the entire text file just to find the number of lines in it. If you are just writing a loop to find one line in the file, you actually don't care how many lines the file has, it is needed only to construct a loop in this way.

Such a collection can still be optimized to work well without random access ability. The hypothetical "lines in a text file" can easily give you each line, in order, quickly and efficiently. The Iterator object holds the current position, and knows how to get the next value, but nobody had to make an index of all the starting positions of all the lines in the file.

In summary, the iterator approach allows you to iterate such collections without having to know ahead of time how many elements there are, and without needing a fast random access method.

share|improve this answer
add comment

Most of the time, both are about equally bad practice.

What you should normally try to do is figure out what the loop accomplishes, and either use an existing algorithm or else write a new algorithm to accomplish that end generically, then apply that algorithm to the collection/range at hand.

Just for example, let's assume you were adding up the items in a vector:

int total = 0;

for (int i=0; i<v.size(); i++)
    total += v[i];

std::cout << "Total = " << total << "\n";

Rewriting this to use iterators is essentially no improvement (and arguably detrimental):

int total = 0;

for (std::vector<int>::iterator p = v.begin(); p!= v.end(); ++p)
    total += *p;

std::cout << "Total = " << total << "\n";

Using C++11, you can at least restore a little sanity:

int total = 0;

for (auto p : v)
    total += p;

std:cout << "Total = " << total << "\n";

...but you don't even need C++11 to to the job quite a bit better still:

std::cout << "Total = " 
          << std::accumulate(v.begin(), v.end(), 0)
          << "\n";

When you find yourself thinking about writing a loop, changing the loop to use an iterator is rarely the right answer -- the right answer is usually to eliminate the loop and replace it with an algorithm instead.

share|improve this answer
1  
Thanks for your answer although I don't agree with it. :) –  user357320 Jan 1 '13 at 23:34
    
How, Mr. Coffin, do you think algorithms like std::accumulate() are implemented? I see your point but I think you're are making way too much of a generalization. There are plenty of valid examples of when a loop should (and need) be used. –  David Cowden Jan 2 '13 at 0:44
    
@DavidCowden: I'm quite well aware of how they're implemented. IMO, using that as a "reason" for writing most loops by hand is equivalent to saying that since a higher level language gets translated into machine code anyway, you might as well do all coding by toggling in machine code on a front panel (and I'm one of the few here old enough to say what a lousy idea that is based on personal experience). –  Jerry Coffin Jan 2 '13 at 2:02
    
@JerryCoffin No, I agree that you should not duplicate standard library function and I understand how preposterous it would be to ask everyone to write in machine code since everything gets translated to that anyway. What I disagree with is the, "there is probably a library for that" mentality and that you should never have to write a for loop. There are cases, like image processing, matrix manipulation, scene graph rendering, etc that need to be fast and for which using for loops expose optimizations and where the efficience lost in abstracting away for loops is unacceptable. –  David Cowden Jan 2 '13 at 5:55
    
@DavidCowden: If you take a look at the output code (e.g., in assembly language) produced by writing a loop inline and using an algorithm, you'll quickly find that the code for the algorithm normally gets expanded inline, so there's no efficiency lost in abstracting away the loop. –  Jerry Coffin Jan 3 '13 at 10:07
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.