6

Johannes Schaub claims here

always use the prefix increment form for iterators whose definitions you don't know. That will ensure your code runs as generic as possible.

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
    /* std::cout << *it; ... */
}

Why doesn't this first iterate it, then start the loop (at v.begin() + 1)?

Community
  • 1
  • 1
jacknad
  • 13,483
  • 40
  • 124
  • 194

3 Answers3

6

Why doesn't this first iterate it, then start the loop (at v.begin() + 1)?

The iteration statement is always executed at the end of each iteration. That is regardless of the type of increment operator you use, or whether you use an increment operator at all.

The result of the iteration statement expression is not used, so it has no effect on how the loop behaves. The statement:

++it;

Is functionally equivalent to the statement:

it++;

Postfix and prefix increment expressions have different behaviour only when the result of the expression is used.


Why use the prefix increment form for iterators?

Because the postfix operation implies a copy. Copying an iterator is generally at least as slow, but potentially slower than not copying an iterator.

A typical implementation of postfix increment:

iterator tmp(*this); // copy
++(*this);           // prefix increment
return tmp;          // return copy of the temporary
                     // (this copy can be elided by NRVO)

When the result is not used, even the first copy can be optimized away but only if the operation is expanded inline. But that is not guaranteed.


I wouldn't blindly use the rule "always use prefix increment with itrators". Some algorithms are clearer to express with postfix, although that is just my opinion. An example of an algorithm suitable for postfix increment:

template<class InIter, class OutIter>
OutIter copy(InIter first, InIter last, OutIter out) {
    while(first != last)
        *out++ = *first++;
    return out;
}
eerorika
  • 232,697
  • 12
  • 197
  • 326
5

Note that your code is equivalent to

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ) {
    /* std::cout << *it; ... */
    ++it;
}

and it should be readily apparent that it doesn't matter if you write ++it; or it++;. (This also addresses your final point.)

But conceptually it++ needs to store, in its implementation, a copy of the unincremented value, as that is what the expression evaluates to.

it might be a big heavy object of which taking a value copy is computationally expensive, and your compiler might not be able to optimise away that implicit value copy taken by it++.

These days, for most containers, a compiler will optimise the arguably clearer it++ to ++it if the value of the expression is not used; i.e. the generated code will be identical.

I follow the author's advice and always use the pre-increment whenever possible, but I am (i) old fashioned and (ii) aware that plenty of expert programmers don't, so it's largely down to personal choice.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
1

Why doesn't this first iterate it, then start the loop (at v.begin() + 1)?

Because the for loop will be parsed as:

{
  init_statement 
  while ( condition ) { 
    statement 
    iteration_expression ; 
  }
}

So

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
    /* std::cout << *it; ... */
}

is equivalent to

{
  std::vector<T>::iterator it = v.begin();
  while ( it != v.end() ) { 
    /* std::cout << *it; ... */
    ++it ; 
  }
}

That means it would do the loop at v.begin() at first, then step forward it. Prefix increment means increase the value and then return the reference of the increased object; As you can seen the returned object is not used at all for this case, then ++it and it++ will lead to the same result.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405