15

I usually iterate over a vector that way:

for (int i = 0; i < myVector.size(); i++) {
    Element* e = myVector[i];
}

But then the compiler usually gives me this warning:

warning: C4018: '<' : signed/unsigned mismatch

So if an int is not right, which type should the index be? vector::size() seems to be of a "size_type" type, but I'd rather use a more meaningful type. Any suggestion?

laurent
  • 88,262
  • 77
  • 290
  • 428

4 Answers4

21

You should use std::vector<T>::size_type1. Its unsigned integral type. Its usually same as size_t.

To know the difference between size_type and size_t, see this topic:

1. Similarly, you can use std::string::size_type, std::list<T>::size_type, std::deque<T>::size_type, std::set<T>::size_type, and so on. Almost all standard containers define a nested type called size_type.


One can argue that you should use iterator instead of index. But I also see that sometime iterator makes the for-loop very wide horizontally, see this :

for(std::vector<std::vector<std::string> >::iterator it = v.begin(); it != v.end(); ++it)
{
}

It doesn't look. It in fact irritates sometimes. In such situations, some programmers prefers index over iterator.

In C++0x, iterator has been made more idiomatic. Now you can use iterator without making the syntax cumbersome:

for(auto it = v.begin(); it != v.end(); ++it)
{  
}

Or even better, using range-based for loop:

for(auto & item : v)
{
}
Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    If you insert elements at the end of the vector, its iterators are invalidated, but indices are unaffected. – jdh8 Jul 31 '19 at 17:56
2

The compiler gives the warning because your int is signed but size() returns an unsigned int of type size_t. You don't want this kind of mismatch because it can cause headaches if your int is negative. You can avoid all of this by using size_t.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
mwd
  • 420
  • 3
  • 12
0

If you are just using it for iteration, then you might want to use:

    typedef std::vector<Element*> ElementContainer;
    ElementContainer myVector(3);

    for (ElementContainer::const_iterator cit = myVector.begin();cit != myVector.end(); ++cit)
    {
        Element* e = *cit;
    }

This has the advantage of being slightly more robust to changing from vector<> to another container.

Keith
  • 6,756
  • 19
  • 23
-1

Just use unsigned. With size_t you never remember what the right header to include is, and with vector<T>::size_type you end up typing too much. For all practical purposes they are the same thing, just retypedefed a dozen of times.

dragonroot
  • 5,653
  • 3
  • 38
  • 63
  • On a typical 64 bit machine, `std::size_t` and `unsigned` are *not* the same thing. – David Hammen Aug 10 '11 at 08:59
  • @David, what would be the different on a 64 bits machine? Could I run into any problem if I use `unsigned int` instead of `size_t`? – laurent Aug 10 '11 at 11:11
  • You'll run into problems using `unsigned int` if the number of items in the vector exceeds 4294967295. If you think your application might even come close to having a vector that is that big you will have known this well in advance. In most cases you will not have any problems using `unsigned int` instead of `std::size_t`. – David Hammen Aug 10 '11 at 12:37
  • 1
    -1 because all it takes to know which one is the best header to include std::size_t is a google search: http://en.cppreference.com/w/cpp/types/size_t and http://en.cppreference.com/w/cpp/header/cstddef – NicoBerrogorry Sep 30 '17 at 16:20