- A+

In Google C++ Style Guide, on the topic of "Unsigned Integers", it suggested that:

Because of historical accident, the C++ standard also uses unsigned integers to represent the size of containers - many members of the standards body believe this to be a mistake, but it is effectively impossible to fix at this point. The fact that unsigned arithmetic doesn't model the behavior of a simple integer, but is instead defined by the standard to model modular arithmetic (wrapping around on overflow/underflow), means that a significant class of bugs cannot be diagnosed by the compiler.

What is wrong with modular arithmetic? Isn't that the expected behaviour of unsigned int?

What kind of bugs (a significant class) does the guide refer to? Overflowing bugs?

Do not use an unsigned type merely to assert that a variable is non-negative.

One reason that I can think of using signed int over unsigned int, is that if it does overflow (to negative), it is easier to detect.

As stated, mixing `unsigned`

and `signed`

might lead to unexpected behaviour (even if well defined).

Suppose you want to iterate over all elements of vector except for the last five, you might wrongly write:

`for (int i = 0; i < v.size() - 5; ++i) { foo(i); } // Incorrect // for (int i = 0; i + 5 < v.size(); ++i) { foo(i); } // Correct `

Suppose `v.size() < 5`

, then, as `v.size()`

is `unsigned`

, `s.size() - 5`

would be a very large number, and so `i < v.size() - 5`

would be `true`

for a more expected range of value of `i`

. And UB then happens quickly (out of bound access once `i >= v.size()`

)

If `v.size()`

would have return signed value, then `s.size() - 5`

would have been negative, and in above case, condition would be false immediately.

On the other side, index should be between `[0; v.size()[`

so `unsigned`

makes sense. Signed has also its own issue as UB with overflow or implementation-defined behaviour for right shift of a negative signed number, but less frequent source of bug for iteration.