[c++] Iteration over std::vector: unsigned vs signed index variable

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?

This question is related to c++ stl unsigned signed

The answer is


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).


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]; ... */
}

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.


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]; ... */
}

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).


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.


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).


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.


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)

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).


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 );

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.


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 );

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.


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.


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 );

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.


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.


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.


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.


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.


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
}

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.


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) {
...

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.


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.


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
}

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.


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.


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.


for (vector<int>::iterator it = polygon.begin(); it != polygon.end(); it++)
    sum += *it; 

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.


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.


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).


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)

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 );

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;
}

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).


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;
}

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) {
...

for (vector<int>::iterator it = polygon.begin(); it != polygon.end(); it++)
    sum += *it; 

Examples related to c++

Method Call Chaining; returning a pointer vs a reference? How can I tell if an algorithm is efficient? Difference between opening a file in binary vs text How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Install Qt on Ubuntu #include errors detected in vscode Cannot open include file: 'stdio.h' - Visual Studio Community 2017 - C++ Error How to fix the error "Windows SDK version 8.1" was not found? Visual Studio 2017 errors on standard headers How do I check if a Key is pressed on C++

Examples related to stl

Why is it OK to return a 'vector' from a function? How to remove all the occurrences of a char in c++ string How to use the priority queue STL for objects? use std::fill to populate vector with increasing numbers What does iterator->second mean? How to set initial size of std::vector? Sorting a vector in descending order How do I reverse a C++ vector? Recommended way to insert elements into map Replace an element into a specific position of a vector

Examples related to unsigned

Unsigned values in C How to use the unsigned Integer in Java 8 and Java 9? How to convert signed to unsigned integer in python should use size_t or ssize_t Declaring an unsigned int in Java Is unsigned integer subtraction defined behavior? Calculating bits required to store decimal number How to cast or convert an unsigned int to int in C? Difference between signed / unsigned char Can we make unsigned byte in Java

Examples related to signed

How to convert signed to unsigned integer in python should use size_t or ssize_t What is the difference between “int” and “uint” / “long” and “ulong”? C++ convert hex string to signed integer Iteration over std::vector: unsigned vs signed index variable How to determine a Python variable's type? Signed versus Unsigned Integers