What is the correct way of iterating over a vector in C++?
Consider these two code fragments, this one works fine:
for (unsigned i=0; i < polygon.size(); i++) {
sum += polygon[i];
}
and this one:
for (int i=0; i < polygon.size(); i++) {
sum += polygon[i];
}
which generates warning: comparison between signed and unsigned integer expressions
.
I'm new in the world of C++, so the unsigned
variable looks a bit frightening to me and I know unsigned
variables can be dangerous if not used correctly, so - is this correct?
For iterating backwards see this answer.
Iterating forwards is almost identical. Just change the iterators / swap decrement by increment. You should prefer iterators. Some people tell you to use std::size_t
as the index variable type. However, that is not portable. Always use the size_type
typedef of the container (While you could get away with only a conversion in the forward iterating case, it could actually go wrong all the way in the backward iterating case when using std::size_t
, in case std::size_t
is wider than what is the typedef of size_type
):
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
/* std::cout << *it; ... */
}
Important is, 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(auto const& value: a) {
/* std::cout << value; ... */
for(std::vector<int>::size_type i = 0; i != v.size(); i++) {
/* std::cout << v[i]; ... */
}
for(element_type* it = a; it != (a + (sizeof a / sizeof *a)); it++) {
/* std::cout << *it; ... */
}
for(auto const& value: a) {
/* std::cout << value; ... */
for(std::size_t i = 0; i != (sizeof a / sizeof *a); i++) {
/* std::cout << a[i]; ... */
}
Read in the backward iterating answer what problem the sizeof
approach can yield to, though.
Four years passed, Google gave me this answer. With the standard C++11 (aka C++0x) there is actually a new pleasant way of doing this (at the price of breaking backward compatibility): the new auto
keyword. It saves you the pain of having to explicitly specify the type of the iterator to use (repeating the vector type again), when it is obvious (to the compiler), which type to use. With v
being your vector
, you can do something like this:
for ( auto i = v.begin(); i != v.end(); i++ ) {
std::cout << *i << std::endl;
}
C++11 goes even further and gives you a special syntax for iterating over collections like vectors. It removes the necessity of writing things that are always the same:
for ( auto &i : v ) {
std::cout << i << std::endl;
}
To see it in a working program, build a file auto.cpp
:
#include <vector>
#include <iostream>
int main(void) {
std::vector<int> v = std::vector<int>();
v.push_back(17);
v.push_back(12);
v.push_back(23);
v.push_back(42);
for ( auto &i : v ) {
std::cout << i << std::endl;
}
return 0;
}
As of writing this, when you compile this with g++, you normally need to set it to work with the new standard by giving an extra flag:
g++ -std=c++0x -o auto auto.cpp
Now you can run the example:
$ ./auto
17
12
23
42
Please note that the instructions on compiling and running are specific to gnu c++ compiler on Linux, the program should be platform (and compiler) independent.
In the specific case in your example, I'd use the STL algorithms to accomplish this.
#include <numeric>
sum = std::accumulate( polygon.begin(), polygon.end(), 0 );
For a more general, but still fairly simple case, I'd go with:
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
using namespace boost::lambda;
std::for_each( polygon.begin(), polygon.end(), sum += _1 );
Regarding Johannes Schaub's answer:
for(std::vector<T*>::iterator it = v.begin(); it != v.end(); ++it) {
...
}
That may work with some compilers but not with gcc. The problem here is the question if std::vector::iterator is a type, a variable (member) or a function (method). We get the following error with gcc:
In member function ‘void MyClass<T>::myMethod()’:
error: expected `;' before ‘it’
error: ‘it’ was not declared in this scope
In member function ‘void MyClass<T>::sort() [with T = MyClass]’:
instantiated from ‘void MyClass<T>::run() [with T = MyClass]’
instantiated from here
dependent-name ‘std::vector<T*,std::allocator<T*> >::iterator’ is parsed as a non-type, but instantiation yields a type
note: say ‘typename std::vector<T*,std::allocator<T*> >::iterator’ if a type is meant
The solution is using the keyword 'typename' as told:
typename std::vector<T*>::iterator it = v.begin();
for( ; it != v.end(); ++it) {
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With