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?
.size()
is not of type unsigned
a.k.a. unsigned int
. It's of type std::size_t
.
std::size_t
is an _implementation-defined typedef. See the Standard. std::size_t
might be equivalent to unsigned
in your current implementation, but that's not relevant. Pretending it is can result in non-portable code and undefined behaviour.
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
):
Using std::vector
Using iterators
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.
Using Range C++11
for(auto const& value: a) {
/* std::cout << value; ... */
Using indices
for(std::vector<int>::size_type i = 0; i != v.size(); i++) {
/* std::cout << v[i]; ... */
}
Using arrays
Using iterators
for(element_type* it = a; it != (a + (sizeof a / sizeof *a)); it++) {
/* std::cout << *it; ... */
}
Using Range C++11
for(auto const& value: a) {
/* std::cout << value; ... */
Using indices
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.
for (auto& val: vec)
std::vector<int> v = std::vector<int>();
, or could you have simply used std::vector<int> v;
instead?
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) {
...
T
is a template argument, and thus the expression std::vector<T*>::iterator
is a dependent name. For a dependent name to be parsed as a type, it needs to be prepended by the typename
keyword, as the diagnostic indicates.
A call to vector<T>::size()
returns a value of type std::vector<T>::size_type
, not int, unsigned int or otherwise.
Also generally iteration over a container in C++ is done using iterators, like this.
std::vector<T>::iterator i = polygon.begin();
std::vector<T>::iterator end = polygon.end();
for(; i != end; i++){
sum += *i;
}
Where T is the type of data you store in the vector.
Or using the different iteration algorithms (std::transform
, std::copy
, std::fill
, std::for_each
et cetera).
Use size_t
:
for (size_t i=0; i < polygon.size(); i++)
Quoting Wikipedia:
The stdlib.h and stddef.h header files define a datatype called size_t which is used to represent the size of an object. Library functions that take sizes expect them to be of type size_t, and the sizeof operator evaluates to size_t. The actual type of size_t is platform-dependent; a common mistake is to assume size_t is the same as unsigned int, which can lead to programming errors, particularly as 64-bit architectures become more prevalent.
#include <cstddef>
rather than <stddef.h>
or, worse, the entirety of [c]stdlib
, and use std::size_t
rather than the unqualified version - and same for any other situation where you have a choice between <cheader>
and <header.h>
.
A bit of history:
To represent whether a number is negative or not computer use a 'sign' bit. int
is a signed data type meaning it can hold positive and negative values (about -2billion to 2billion). Unsigned
can only store positive numbers (and since it doesn't waste a bit on metadata it can store more: 0 to about 4billion).
std::vector::size()
returns an unsigned
, for how could a vector have negative length?
The warning is telling you that the right operand of your inequality statement can hold more data then the left.
Essentially if you have a vector with more then 2 billion entries and you use an integer to index into you'll hit overflow problems (the int will wrap back around to negative 2 billion).
I usually use BOOST_FOREACH:
#include <boost/foreach.hpp>
BOOST_FOREACH( vector_type::value_type& value, v ) {
// do something with 'value'
}
It works on STL containers, arrays, C-style strings, etc.
To be complete, C++11 syntax enables just one another version for iterators (ref):
for(auto it=std::begin(polygon); it!=std::end(polygon); ++it) {
// do something with *it
}
Which is also comfortable for reverse iteration
for(auto it=std::end(polygon)-1; it!=std::begin(polygon)-1; --it) {
// do something with *it
}
In C++11
I would use general algorithms like for_each
to avoid searching for the right type of iterator and lambda expression to avoid extra named functions/objects.
The short "pretty" example for your particular case (assuming polygon is a vector of integers):
for_each(polygon.begin(), polygon.end(), [&sum](int i){ sum += i; });
tested on: http://ideone.com/i6Ethd
Dont' forget to include: algorithm and, of course, vector :)
Microsoft has actually also a nice example on this:
source: http://msdn.microsoft.com/en-us/library/dd293608.aspx
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// Create a vector object that contains 10 elements.
vector<int> v;
for (int i = 1; i < 10; ++i) {
v.push_back(i);
}
// Count the number of even numbers in the vector by
// using the for_each function and a lambda.
int evenCount = 0;
for_each(v.begin(), v.end(), [&evenCount] (int n) {
cout << n;
if (n % 2 == 0) {
cout << " is even " << endl;
++evenCount;
} else {
cout << " is odd " << endl;
}
});
// Print the count of even numbers to the console.
cout << "There are " << evenCount
<< " even numbers in the vector." << endl;
}
for (vector<int>::iterator it = polygon.begin(); it != polygon.end(); it++)
sum += *it;
The first is type correct, and correct in some strict sense. (If you think about is, size can never be less than zero.) That warning strikes me as one of the good candidates for being ignored, though.
i == INT_MAX
, then i++
causes undefined behavior. At this point anything can happen.
Consider whether you need to iterate at all
The <algorithm>
standard header provides us with facilities for this:
using std::begin; // allows argument-dependent lookup even
using std::end; // if the container type is unknown here
auto sum = std::accumulate(begin(polygon), end(polygon), 0);
Other functions in the algorithm library perform common tasks - make sure you know what's available if you want to save yourself effort.
Obscure but important detail: if you say "for(auto it)" as follows, you get a copy of the object, not the actual element:
struct Xs{int i} x;
x.i = 0;
vector <Xs> v;
v.push_back(x);
for(auto it : v)
it.i = 1; // doesn't change the element v[0]
To modify the elements of the vector, you need to define the iterator as a reference:
for(auto &it : v)
If your compiler supports it, you could use a range based for to access the vector elements:
vector<float> vertices{ 1.0, 2.0, 3.0 };
for(float vertex: vertices){
std::cout << vertex << " ";
}
Prints: 1 2 3 . Note, you can't use this technique for changing the elements of the vector.
Adding this as I couldn't find it mentioned in any answer: for index-based iteration, we can use decltype(vec_name.size())
which would evaluate to std::vector<T>::size_type
Example
for(decltype(v.size()) i{ 0 }; i < v.size(); i++) {
/* std::cout << v[i]; ... */
}
The two code segments work the same. However, unsigned int" route is correct. Using unsigned int types will work better with the vector in the instance you used it. Calling the size() member function on a vector returns an unsigned integer value, so you want to be comparing the variable "i" to a value of its own type.
Also, if you are still a little uneasy about how "unsigned int" looks in your code, try "uint". This is basically a shortened version of "unsigned int" and it works exactly the same. You also don't need to include other headers to use it.
auto polygonsize = polygon.size(), i=polygonsize;
for (i=0; i < polygonsize; i++) {
sum += polygon[i];
}
This
uses auto to avoid us worrying about types.
It takes any function calls e.g. the size() function call out of the loop to avoid unnecessary repeated function calls.
It makes the loop counter available. Purists will want to work with the n'th element with no knowledge of the value of n, and see this as bad.
It appears to have an unecessary statement i=polygonsize initializing the loop variable when it's declared, but this should disappear if there is a half decent code optimizer, and is merely to ensure i has the correct type.
I am not saying anyone should code anything the way I just did.
I am merely offering it as another alternative which avoids worrying about types, takes function calls out of the loop, and makes the loop counter available for practical things like debugging information in more complex scenarios.
Success story sharing
for (auto p : polygon){sum += p;}