I think the [answer of rwong above][1] already excellently highlights the issues. I'll add my 002: * [`size_t`][2], that is, a size that ... > can store the maximum size of a theoretically possible object of any type (including array). ... is only required for range indices when `sizeof(type)==1`, that is, if you're dealing with byte (`char`) types. (But, we note, [it can be smaller than a ptr type][3]: * As such, `xxx::size_type` could be used in 99.9% cases even if it were a signed sized type. (compare [`ssize_t`][4]) * The fact that `std::vector` and friends chose `size_t`, an **unsigned** type, for the size and indexing is [considered by some][5] to be a design flaw. I concur. (Seriously, take 5 minutes and watch the [lightning talk CppCon 2016: Jon Kalb “unsigned: A Guideline for Better Code"][5].) * When you design an C++ API today, you're in a tight place: Use `size_t` to be consistent with the Standard Library, or use (a *signed*) **`intptr_t`** or `ssize_t` for easy and less bug prone indexing calculations. * Don't use int32 or int64 - use `intptr_t` if you want to go signed, and want machine word size, or use `ssize_t`. To directly answer the question, it is not entirely an "historical artefact", as the theoretical issue of needing to address more than half the ("indexing", or) address space *must* be, aehm, addressed somehow in a low level language like C++. In hindsight, I, *personally*, think, it **is** a design flaw that the Standard Library uses unsigned `size_t` all over the place even where it does not represent a raw memory size, but a capacity of typed data, like for the collections: * *given C++s integer promotion rules* -> * unsigned types just don't make good candidates for "semantic" types for something like a size that is semantically unsigned. I'll repeat [Jon's advice][6] here: * Select types for the operations they support (not the range of values). (*1) * Don't use unsigned types in you API. This hides bugs with no upside benefit. * Don't use "unsigned" for quantities.(*2) (*1) i.e. unsigned == bitmask, never do math on it (here hits the first exception - you may need a counter that wraps - this must be an unsigned type.) (*2) quantities meaning something you count and/or do math on. [1]: https://softwareengineering.stackexchange.com/a/338107/6559 [2]: https://en.cppreference.com/w/cpp/types/size_t [3]: https://stackoverflow.com/questions/1464174/size-t-vs-uintptr-t [4]: https://www.gnu.org/software/libc/manual/html_node/I_002fO-Primitives.html [5]: https://www.youtube.com/watch?v=wvtFGa6XJDU [6]: https://youtu.be/wvtFGa6XJDU?t=358