Unsigned integers (size_t, uint32_t, and friends) can be hazardous, as signed-to-unsigned integer conversions can happen without so much as a compiler warning.

An example: size_t as an index variable

Occasionally, discussions come up about using unsigned integers as index variables for STL containers (whose size() attribute is unsigned). So the debate is between effectively these two alternatives:

#include <iostream>

void do_something_unsigned(size_t i) {
  std::cout << "I see: " << i << std::endl;

void do_something_signed(int i) {
  std::cout << "I see: " << i << std::endl;

int main(void) {
  return 0;

This compiles in gcc with no warnings (unless you set -Wconversion, but in general this results in a huge amount of warnings), and the results are not what you expect:

$ ./a.out
I see: 18446744073709551615
I see: -1

Since this programmer mistake can happen by accident due to pointer arithmetic errors and other buglets, you're sometimes looking at a segfault or core dump rather than a more sane error message.

Pedantic note: for platforms with 32-bit int and concerns about overflows, substitute int64_t for the purposes of this discussion.

What to do instead

The Google C++ style guide recommends avoiding unsigned integers except in situations that definitely require it (for example: file formats often store sizes in uint32_t or uint64_t -- no point in wasting a signedness bit that will never be used).

"In particular, do not use unsigned types to say a number will never be negative. Instead, use assertions for this." - Google C++ Style Guide

You also do need to be able to check if a variable that should not be negative ended up being accidentally negative. One approach that many Google projects (and projects developing in the Google style, like the Apache incubator projects Impala and Kudu) take is using DCHECK macros:

void do_something_signed(int i) {
  DCHECK(i >= 0) << "i cannot be negative";
  std::cout << "I see: " << i << std::endl;

These assertions are generally disabled in release builds, but while you are developing a project in DEBUG mode (and running your test suite), you get helpful error messages when you break a "can't happen" contract without suffering a performance penalty in production.

Of course, like all things C++-related, this is just my opinion. Feel free to use unsigned integers for function arguments, but they may not buy you the protection from negative numbers that you're after.