491

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.

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?

starball
  • 20,030
  • 7
  • 43
  • 238
Yuval Adam
  • 161,610
  • 92
  • 305
  • 395
  • 11
    The unsigned one is correct because polygon.size() is of type unsigned. Unsigned means positive always or 0. That's all it means. So if the usage of the variable is always only for counts then unsigned is the right choice. – Adam Bruss Oct 10 '13 at 16:42
  • To solve warning about signed/unsigned just replace `int` by `uint` (`unsigned int`) in `i` declaration. – Honza Dec 21 '14 at 18:30
  • 3
    @AdamBruss `.size()` is not of type `unsigned` a.k.a. `unsigned int`. It's of type `std::size_t`. – underscore_d Jun 26 '16 at 10:15
  • 1
    @underscore_d size_t is an alias for unsigned. – Adam Bruss Jun 27 '16 at 13:39
  • 5
    @AdamBruss No. `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. – underscore_d Jun 27 '16 at 13:45
  • @underscore_d In what version of C++ is unsigned not equivalent to size_t? – Adam Bruss Jun 28 '16 at 14:16
  • 1
    @underscore_d I was wrong in saying unsigned is equivalent to size_t. size_t is 8 bytes under a 64bit build as you pointed out. This is true in microsoft visual c++ as well. But if size_t actually differed across two compilers, as you infer it could, you'd have non-portable code simply by using size_t. – Adam Bruss Jun 28 '16 at 15:22
  • @AdamBruss ...touché! Beaten using my own logic, making my rant in my last comment look hypocritical :-) Yes, implementation-defined behaviour seems guaranteed with typedefs like this, whether one is using or ignoring them. I'd say it's arguably better to use them where available, even if the benefit is purely theoretical - but contrast that to other threads where people argue that `std::size_t` is largely pointless and all normal looping should be done with `int`! I guess these aren't really practical topics, since few people will ever use such large arrays. – underscore_d Jun 28 '16 at 15:31
  • @underscore_d I guess size_t is a necessary evil to allow one size() function for example instead of one that returns a 4 byte unsigned and one that returns an 8 byte unsigned. I agree about the large containers thing. – Adam Bruss Jun 30 '16 at 16:35
  • 1
    @underscore_d It's not of type `size_t`, it is of type `decltype(polygon)::size_type`. – L. F. Jul 31 '19 at 01:50

18 Answers18

857

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.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • size type of pointers: using difference_type might be more portable. try iterator_traits::difference_type. this is one mouthful of a declaration, but it is more portable... – wilhelmtell Jan 04 '09 at 04:48
  • wilhelmtell, for what should i use difference_type? sizeof is defined to return size_t :) i don't understand you. if i were to subtract pointers from each other, difference_type would be the right choice. – Johannes Schaub - litb Jan 04 '09 at 09:38
  • iteration over arrays using the technique that you have mentioned in this post won't work if the iteration is being performed in a function on an array passed to that function. Because sizeof array will only return the sizeof pointer. – systemsfault Jun 07 '11 at 08:33
  • Accodring to this [1] guide using unsinged loop counters is a bad idea. So one should probably cast size first in a signed int. [1] http://developer.download.nvidia.com/compute/cuda/3_1/toolkit/docs/NVIDIA_CUDA_C_BestPracticesGuide_3.1.pdf – Nils Feb 23 '12 at 15:03
  • 1
    @Nils i agree that using unsigned loop counters is a bad idea. but because the standard library uses unsigned integer types for index and size, i prefer unsigned index types for the standard library. other libraries consequently only use signed types, like the Qt lib. – Johannes Schaub - litb Mar 11 '12 at 16:53
  • 33
    Update for C++11: range based for loop. `for (auto p : polygon){sum += p;}` – Siyuan Ren Aug 22 '13 at 04:56
  • @C.R. also update for C++11: Use `std::begin()` and `std::end()` to make the array and vector version equal. – Manu343726 Oct 19 '13 at 15:01
  • @StackedCrooked I posted a C++11-Answer about a year ago, see further down: http://stackoverflow.com/questions/409348/iteration-over-vector-in-c/15229929#15229929 – kratenko Apr 29 '14 at 09:27
  • if you have to use a loop index and are too lazy to type out the full `size_type` of the container, consider another C++11 feature `decltype`, as in `for (decltype(vec.size()) i=0; i – Yibo Yang May 25 '17 at 06:05
  • @JohannesSchaub-litb The "Using std::vector / Using Range C++11" example looks wrong to me. Where does the "const &" requierement come from? Should the example not be: `for(auto i : v) { /* std::cout << i; ... */ }`? – stackprotector Jun 10 '20 at 10:12
180

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.

Ziezi
  • 6,375
  • 3
  • 39
  • 49
kratenko
  • 7,354
  • 4
  • 36
  • 61
  • 9
    C++11 gives you `for (auto& val: vec)` – Flexo Mar 05 '13 at 18:57
  • 1
    @flexo Thanks, I don't know how I could forget that. Not doing enough C++, I guess. Couldn't believe there's something that practical (thought that was JavaScript syntax, actually). I changed the answer to include that. – kratenko Mar 08 '13 at 09:34
  • Your answer is very nice. It is unpleased that default version of g++ in various OS devkits is under 4.3 which makes it not work. – Ratata Tata Aug 28 '13 at 14:05
  • Do you need to initialise the vector with `std::vector v = std::vector();`, or could you have simply used `std::vector v;` instead? – Bill Cheatham Mar 27 '16 at 13:59
  • @BillCheatham Well - I just tried it out without the initialising, and it did work, so it seems it works without. – kratenko Mar 27 '16 at 15:08
  • Thanks, yes it worked for me to but I wondered if I was just getting lucky with memory and not getting a segfault. I suppose `std::vector`s shouldn't have the same problems that arrays can...? – Bill Cheatham Mar 27 '16 at 15:40
  • I find it strange that you wrote an answer to praise new features of C++11 and yet initialised your container like _that_ instead of using C++11's `std::initializer_list`, which exists precisely to avoid such boilerplate. Just do this: `std::vector v{17, 12, 23, 42};`. That avoids the unnecessary default construction from an even more unnecessary temporary and the repeated `push_back()` - and btw, we should default to using another new C++11 thing, `emplace_back()`, since at least for more complex objects, `push` might generate unnecessary copy-constructions. – underscore_d Jun 26 '16 at 10:17
  • You don't need the & for the read-only access and I think int would be better than auto here personally: I'd use: for ( int i : v ) – Will Jun 19 '17 at 09:52
  • I would like to know ,How the "for (auto& val: vec)" works internally , it is using the iterator internally and begin(), end() functions of the vector class ? – Vineesh Vijayan Nov 05 '20 at 05:46
43

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 );
oz10
  • 153,307
  • 27
  • 93
  • 128
38

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) {
...
Polat Tuzla
  • 2,073
  • 2
  • 13
  • 4
  • 2
    You should elaborate that this only applies when `T` is a template argument, and thus the expression `std::vector::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. – Kuba hasn't forgotten Monica Jul 31 '14 at 13:22
17

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

Jasper Bekkers
  • 6,711
  • 32
  • 46
  • Iterators are generally a good idea, though i doubt there's a need to store "end" in a separate variable and it can all be done inside a for(;;) statement. – Saulius Žemaitaitis Jan 03 '09 at 17:03
  • 1
    I know begin() and end() are amortized constant time, but I generally find this to be more readable than to cram everything into one line. – Jasper Bekkers Jan 03 '09 at 17:06
  • 3
    You can split the for into separate lines to improve readability. Declaring iterators outside the loop means you need a different iterator name for every loop over containers of different types. – Jay Conrod Jan 03 '09 at 17:43
  • I am aware of all the differences, and what it basically comes down to is personal preference; this is generally how I end up doing things. – Jasper Bekkers Jan 04 '09 at 18:23
  • it is generally recommended you store the result of end() in a variable to avoid the repeated function call. even if it's constant time, there is still overhead in making the call. there is no reason to initialize outside the loop and the only result of that is cluttering the scope. – user44511 Jan 04 '09 at 18:43
  • @user44511: so what is your suggestion? – pihentagy Jun 28 '11 at 09:31
  • 2
    @pihentagy I guess that would be to set it in the first section of the for-loop. eg. for(auto i = polygon.begin(), end = polygon.end(); i != end; i++) – Jasper Bekkers Jan 08 '14 at 20:58
  • any operation that invalidates iterators, also potentially invalidates end() – sp2danny Nov 12 '14 at 10:44
12

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.

Community
  • 1
  • 1
Igor
  • 26,650
  • 27
  • 89
  • 114
  • size_t OK for vector, as it must store all objects in an array (itself an object, too) but a std::list may contain more than size_t elements! – MSalters Jan 05 '09 at 09:57
  • 1
    size_t is normally sufficient to enumerate all bytes in address space of a process. While I can see how this may not be the case on some exotic architectures, I'd rather not worry about it. –  Jan 05 '09 at 18:54
  • AFAIK it's recommended to `#include ` rather than `` 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 `` and ``. – underscore_d Jun 26 '16 at 10:24
7

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

sudo_coffee
  • 888
  • 1
  • 12
  • 26
ecoffey
  • 3,423
  • 4
  • 23
  • 22
6

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.

Martin Cote
  • 28,864
  • 15
  • 75
  • 99
  • 2
    Good answer to some other question (how should I iterate a vector?), but completely not at all what the OP was asking (what is the meaning of the warning about an unsigned variable?) – abelenky Jan 03 '09 at 17:39
  • 3
    Well, he asked what the correct way of iterating over a vector was. So seems relevant enough. The warning is just why he's not happy with his current solution. – jalf Jan 03 '09 at 18:14
5

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
}
Jan Turoň
  • 31,451
  • 23
  • 125
  • 169
5

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;
}
Community
  • 1
  • 1
jave.web
  • 13,880
  • 12
  • 91
  • 125
4
for (vector<int>::iterator it = polygon.begin(); it != polygon.end(); it++)
    sum += *it; 
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • 2
    For vector this is fine, but generically it's better to use ++it rather than it++, in case the iterator itself is non-trivial. – Steve Jessop Jan 04 '09 at 13:50
  • Personally, I am used to using ++i, but I think most people prefer i++ style (the default VS code snippet for "for" is i++). Just a thought – Mehrdad Afshari Jan 04 '09 at 18:31
  • @MehrdadAfshari Who cares what "most people" do? "most people" are wrong about lots of things. Post-inc/decrement where the pre value is never used is wrong and inefficient, at least in theory - regardless of how often it's blindly used in sub-par example code everywhere. You shouldn't encourage bad practices just to make things look more familiar to people who don't yet know better. – underscore_d Jun 26 '16 at 10:27
2

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.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • 2
    I think it's a terrible candidate to be ignored - it's easy to fix, and once in a while genuine bugs occur due to errors comparing signed/unsigned values inappropriately. For instance in this case, if the size is greater than INT_MAX the loop never terminates. – Steve Jessop Jan 04 '09 at 13:54
  • ... or maybe it terminates immediately. One of the two. Depends whether the signed value is converted to unsigned for comparison, or the unsigned is converted to signed. On a 64bit platform with a 32bit int, though, like win64, the int would be promoted to size_t, and the loop never ends. – Steve Jessop Jan 04 '09 at 14:28
  • @SteveJessop: You can't say with certainty the loop never ends. On the iteration when `i == INT_MAX`, then `i++` causes undefined behavior. At this point anything can happen. – Ben Voigt Oct 16 '14 at 17:21
  • @BenVoigt: true, and still doesn't provide grounds to ignore the warning :-) – Steve Jessop Oct 19 '14 at 12:35
2

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.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
1

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)
Pierre
  • 4,114
  • 2
  • 34
  • 39
1

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.

Brett L
  • 105
  • 1
  • 11
1

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]; ... */
}
Community
  • 1
  • 1
Bharat S
  • 334
  • 1
  • 8
0

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.

  • Unsigned integer for size() does not necessarily equal to "unsigned int" in C++ terms, often 'unsigned integer' in this case is a 64bit unsigned integer while 'unsigned int' is usually 32bits. – Medran Mar 07 '19 at 16:12
0
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.

Ivan
  • 41
  • 4