This answer truly depends on who is going to use your code, and what standards they want to see.
size_t
is an integer size with a purpose:
The type size_t
is an implementation-defined unsigned integer type that is large enough to contain the size in bytes of any object. (C++11 specification 18.2.6)
Thus, any time you wish to work with the size of objects in bytes, you should use size_t
. Now in many cases, you're not using these dimensions/indexes to count bytes, but most developers choose to use size_t
there for consistency.
Note that you should always use size_t
if your class is intended to have the look and feel of a STL class. All of the STL classes in the specification use size_t
. It is valid for the compiler to typedef size_t
to be unsigned int
, and it's also valid for it to be typedefed to unsigned long
. If you use int
or long
directly, you'll eventually run into compilers where a person who thinks your class followed the STL's style gets trapped because you didn't follow the standard.
As for using signed types, there's a few advantages:
- Shorter names -- it's really easy for people to type
int
, but much harder to clutter the code with unsigned int
.
- One integer for each size -- There is only one CLS compliant integer of 32-bits, which is Int32. In C++, there's two (
int32_t
and uint32_t
). This can make API interoperability simpler
The big disadvantage of signed types is the obvious one: you lose half of your domain. A signed number cannot count as high as an unsigned number. When C/C++ came around, this was very important. One needed to be able to address the full capability of the processor, and to do that you needed to use unsigned numbers.
For the kinds of applications .NET targeted, there was not as strong of a need for a full-domain unsigned index. Many of the purposes for such numbers are simply invalid in a managed language (memory pooling comes to mind). Also, as .NET came out, 64-bit computers were clearly the future. We're a long way away from needing the full range of a 64-bit integer, so sacrificing one bit is not as painful as it was before. If you really need 4 billion indexes, you simply switch to using 64-bit integers. At worst, you run it on a 32 bit machine and it's a little slow.
I view the trade as one of convenience. If you happen to have enough computing power that you don't mind wasting a bit of your index type that you will never-ever-ever use, then it's convenient to just type int
or long
and walk away from it. If you find you really wanted that last bit, then you probably should have paid attention to the signedness of your numbers.
-1
is returned from functions that return an index, to indicate "not found" or "out of range." It's also returned fromCompare()
functions (implementingIComparable
). A 32 bit int is considered the go to type for a general number, for what I hope are obvious reasons.