We use Integer type represent index variables most of the time. But in some situations, we're forced to choose

std::vector<int> vec;
....
for(int i = 0; i < vec.size(); ++i)
....

This will cause the compiler to raise the warning that mixed use of signed/unsigned variables. if I make the index variable as for( size_t i = 0; i < vec.size(); i++ ), (or an unsigned int )it will sort out the issues.

When it come more specific to use windows types, most of the Windows APIs are dealing with DWORD (which typedef-ed as unsigned long).

So when I use similar iteration, will again cause the same warning. Now if I rewrite it as

DWORD dwCount;
....
for(DWORD i = 0; i < dwCount; ++i)
....

I find this a bit weird. It might be the problem withe perceptions.

I agree that we are supposed to use the same type of index variable to avoid the range problems can happen with the index variables. For e.g if we're using

_int64 i64Count; //
....
for(_int64 i = 0; i < i64Count; ++i)
....

But in the case of DWORD, or unsigned integers, are there any problems in rewriting it as

Why would you use a signed integer to represent index? That's like using vector of integers to store a string.
–
Let_Me_BeAug 30 '11 at 9:46

1

@Let_Me_Be: Because it makes the boundary conditions easier to test. For example on a count down to zero, a less-than test before executing the loop body cannot work with an unsigned value. Similarly a count up to the maximum doesn't work. Of course in that case a signed integer won't work either (because it can't represent such a large value).
–
YttrillJan 13 '12 at 20:03

for (std::vector<int>::iterator i = vec.begin(); i != vec.end(); ++i) is a pain to write. Having for (auto i = vec.begin();... is a whole lot more readable. Of course, foreach is also in C++11.
–
David ThornleyAug 30 '11 at 14:12

The reason it's warning you about comparison between signed and unsigned is because the signed value will likely be converted to unsigned, which might not be what you expect.

In your example (comparing int to size_t), int will be implicitly converted to size_t (unless int somehow has a larger range than size_t). Thus, if the int is negative, it will likely be greater than the value you're comparing it to due to wraparound. This won't be a problem if your index is never negative, but you'll still get that warning.

Instead, use an unsigned type (such as unsigned int, size_t, or, as John B recommends, std::vector<int>::size_type) for your index variable:

for(unsigned int i = 0; i < vec.size(); i++)

Be careful when counting down, though:

for(unsigned int i = vec.size()-1; i >= 0; i--) // don't do this!

The above will not work because i >= 0 is always true when i is unsigned. Instead, use the "arrow operator" for loops that count down:

for (unsigned int i = vec.size(); i-- > 0; )
vec[i] = ...;

As other answers point out, you normally want to use an iterator to traverse a vector. Here's the C++11 syntax:

But shouldn't this just delcare i as int, because 0 is an int literal and the auto keyword doesn't "look ahead" to the i < vec.size() expression? Or is a for loop treated with special intelligence by the compiler?
–
Christian RauAug 30 '11 at 16:48

1

@Cristian: Yes, a good catch. auto works well with iterators because you initialize it with vec.begin(). Unfortunatelly, with indices that does not work. My bad :)
–
Nemanja TrifunovicAug 30 '11 at 17:02

2

Please adjust your answer; not everyone reading it will also read the comments.
–
Mihai DanilaJan 1 '14 at 6:31

While it repeats a little more than the basic for-loop would, it's not nearly as long-winded as pre-'11 ways of specifying values, and using this pattern consistently will work for most, if not all, possible terms you'd want to compare against, which makes it great for code refactoring. It even works for simple cases like this:

int x = 3; int final = 32; for(decltype(final) i = x; i < final; ++i)

Furthermore, while you should use auto whenever you're setting i to some intelligent value (like vec.begin()), decltype works when you're setting to a constant like zero, where auto would just resolve that to int because 0 is a simple integer literal.

To be honest, I'd like to see a compiler mechanism for extending the auto type-determination for loop incrementers to look at the value being compared against.

I use a cast to int, as in for (int i = 0; i < (int)v.size(); ++i). Yes, it's ugly. I blame it on the stupid design of the standard library where they decided to use unsigned integers to represent sizes. (In order to.. what? extend the range by one bit?)

In what situation would a collection size of negative anything be meaningful? Using unsigned integers for various collection sizes seems like the sensible choice, to me. Last I checked, taking the length of a string rarely returned a negative result either...
–
Michael KjörlingAug 31 '11 at 8:11

In what situation would it be meaningful for simple test such as if(v.size()-1 > 0) { ... } to return true for an empty container? The problem is that sizes are also often used in arithmetic, esp. with index-based containers, which is asking for trouble given that they're unsigned. Basically, using unsigned types for anything else than 1) bitwise manipulations, or 2) modular arithmetic is calling for trouble.
–
zvrbaSep 1 '11 at 6:11

2

good point. While I don't really see the point of your particular example (I would probably just write if(v.size() > 1) { ... } since that makes the intent more clear, and as an added bonus the issue of signed/unsigned becomes void), I do see how in some specific cases signedness might be useful. I stand corrected.
–
Michael KjörlingSep 2 '11 at 20:59

@Michael: I agree it was contrived example. Still, I often write algorithms with nested loops: for(i=0;i<v.size()-1;++i) for(j=i+1;j<v.size();++j) .. if v is empty, the outer loop executes (size_t)-1 times. So I either have to check v.empty() before the loop or cast v.size() to a signed type, both of which I personally think are ugly workarounds. I choose a cast as it's fewer LOC, no if()s => fewer possibilites for mistake. (Also, in 2nd complement, conversion oveflow returns a negative number, so the loop doesn't execute at all.)
–
zvrbaSep 3 '11 at 9:44