Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate through a C++ Vector using a 'for' loop

The reason why you don't see such practice is quite subjective and cannot have a definite answer, because I have seen many of the code which uses your mentioned way rather than iterator style code.

Following can be reasons of people not considering vector.size() way of looping:

  1. Being paranoid about calling size() every time in the loop condition. However either it's a non-issue or it can be trivially fixed
  2. Preferring std::for_each() over the for loop itself
  3. Later changing the container from std::vector to other one (e.g. map, list) will also demand the change of the looping mechanism, because not every container support size() style of looping

C++11 provides a good facility to move through the containers. That is called "range based for loop" (or "enhanced for loop" in Java).

With little code you can traverse through the full (mandatory!) std::vector:

vector<int> vi;
...
for(int i : vi) 
  cout << "i = " << i << endl;

Is there any reason I don't see this in C++? Is it bad practice?

No. It is not a bad practice, but the following approach renders your code certain flexibility.

Usually, pre-C++11 the code for iterating over container elements uses iterators, something like:

std::vector<int>::iterator it = vector.begin();

This is because it makes the code more flexible.

All standard library containers support and provide iterators. If at a later point of development you need to switch to another container, then this code does not need to be changed.

Note: Writing code which works with every possible standard library container is not as easy as it might seem to be.


The cleanest way of iterating through a vector is via iterators:

for (auto it = begin (vector); it != end (vector); ++it) {
    it->doSomething ();
}

or (equivalent to the above)

for (auto & element : vector) {
    element.doSomething ();
}

Prior to C++0x, you have to replace auto by the iterator type and use member functions instead of global functions begin and end.

This probably is what you have seen. Compared to the approach you mention, the advantage is that you do not heavily depend on the type of vector. If you change vector to a different "collection-type" class, your code will probably still work. You can, however, do something similar in Java as well. There is not much difference conceptually; C++, however, uses templates to implement this (as compared to generics in Java); hence the approach will work for all types for which begin and end functions are defined, even for non-class types such as static arrays. See here: How does the range-based for work for plain arrays?


The right way to do that is:

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

Where T is the type of the class inside the vector. For example if the class was CActivity, just write CActivity instead of T.

This type of method will work on every STL (Not only vectors, which is a bit better).

If you still want to use indexes, the way is:

for(std::vector<T>::size_type i = 0; i != v.size(); i++) {
    v[i].doSomething();
}