5

I have a vector declared as

std::vector<int> MyVector; MyVector.push_back(5); MyVector.push_back(6); MyVector.push_back(7); 

How do should I use it in a for loop?

By iterating it with an iterator?

for (std::vector<int>::iterator it=MyVector.begin(); it!=MyVector.end(); ++it) { std::cout << "Vector element (*it): " << *it << std::endl; } 

Or by its access iterator?

for (std::vector<int>::size_type i=0; i<MyVector.size(); i++) { std::cout << "Vector element (i) : " << MyVector.at(i) << std::endl; } 

In examples I found on internet both of them are used. Is one of them superior to the other under all conditions? If not, when should I prefer one of them over the other?

1
  • 1
    Doesn't the name "iterator" help with the decision? By the way, I hope you have a clear understanding of what std::vector::at does and why you use it in your code. If using std::vector::at instead of std::vector::operator[], iterators will most probably always be faster (disregarding any other advantages). Commented Sep 24, 2012 at 7:46

4 Answers 4

5

The first format is more generic format for iterating over standard library containers so it is more common and intuitive. If you need to change your container then this iterating code remains unimpacted.It will work for every standard library container type, thus it gives you more generic code.

In second format, std::vector::at() checks for the bounds each time it gets called on every iteration, so it may be a little detrimental to performance. This overhead is not present in the first format as there is no bounds checking involved.Note that same is the case with using operator[].
Note the performance lag though is not as much as you will notice it unless you are operating on a huge data.

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

4 Comments

Concur. Bottom line: use iterators for scanning, at() for random access. you'll be glad you did.
@CraigNelson No, I won't. If I access the vector out of bounds, then shame (and UB) on me, but don't make me check its size each and every time. In debug mode I'll get an assertion anyway (at least in VC++).
@ChristianRau if you're random-accessing a sequence without knowing the bounds thats your business. I prefer to know that ahead of time. You're quite right, however. I meant to say [] rather than at(). touche.
The iterator or operator[] will normally do bounds checking as well (although you can usually turn it off if necessary for performance reasons). The difference between their bounds checking and that in at() is that an error will crash the program (which is usually what you want), rather than triggering an exception which you can't reasonably handle.
3

Using std::vector's [] operator is probably faster because using std::vector::at() inside a for loop checks the vector's size twice (in the for loop and in std::vector::at()'s bounds checking).

The first method can be used in other containers and thus can help you much when you change your container type.

If you use C++11, use range-based loops.

Comments

2

First if you have C++11, use a range-based for:

for (auto i : MyVector) { std::cout << i; } 

Or BOOST_FOREACH in C++03:

BOOST_FOREACH(int& i, MyVector) { std::cout << i; } 

Or std::copy:

std::copy(MyVector.begin(), MyVector.end(), std::ostream_iterator<int>(std::cout, "\n")); 

As for, the question at hand, at() checks that the index is within bounds and throws an exception if it isn't. So, do not use it unless you need that extra checking. The first way you have it is standard and works well. Some people are pedantic and even it write it like so:

for (std::vector<int>::iterator it=MyVector.begin(), end = MyVector.end(); it!= end; ++it) { std::cout << "Vector element (*it): " << *it << std::endl; } 

In the above I cached the end iterator instead of calling end() each loop. Whether this actually makes a performance difference or not, I don't know.

Comments

1

There is no "one is superior to the other" (except that you almost never want to use at()at() is only appropriate if there is something you can really do to recover from the error). The use of iterator vs. index is largely one of style, and the message you're passing. The more idiomatic C++ way of doing things would be the iterator, but people coming from other backgrounds (for example, mathematicians) will find indexing more idiomatic.

There are where there is a real distinction:

  • The iterator idiom will work with other types of containers. This might be relevant if there is a real possibility that you use other containers.

  • The indexing idiom can use a single index for several different containers. If you're iterating through several vector with the same size, using the indexing idiom makes it clearer that you're accessing the same element in each of the vector. (Again, this seems to occur most often in mathematical applications.)

  • Finally, any time you're really doing random access, or calculating the element in any way, using indexes is probably more intuitive. (In such cases, you probably want to do the calculations in int, only converting to size_t at the last moment.)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.