C++: Is there any reason to use uint64_t instead of size_t

11,763

Solution 1

size_t is the return-type of sizeof.

The standard says it's a typedef of some unsigned integer type, and large enough to hold the size of any possible object.
But it does not mandate whether it is smaller, bigger, or the same size as uint64_t (a typedef for a fixed-width 64-bit unsigned integer), nor in the latter case whether it is the same type.

Thus, use size_t where semantically correct.
Like for the size() of a std::vector<T> (std::vector gets it's size_type from the used allocator, std::allocator<T> using size_t).

Solution 2

uint64_t is guaranteed to be 64 bits. If you need 64 bits, you should use it.

size_t isn't guaranteed to be 64 bits; it could be 128 bits in a future machine. So, keyword uint_64 its reserved by that :)

Solution 3

The correct case would be for(std::vector::size_type i ....

For the purpose of iterating through a vector, or something of that sort, you would be hard pushed to find a case where size_t isn't big enough, and uint64_t is,

Of course, on a 32-bit machine, size_t would typically be 32 bits, but you may want to deal with numbers larger than 4 billion, which would require more than 32 bits, and this is certainly a use-case fo uint64_t. In other words, uint64_t is guaranteed to be 64-bit, size_t is not 64 bits in all machines/architectures.

Solution 4

std::size_t is defined as an unsigned integer type. Its length depends on the platform. v.size() will always return a value of type std::size_t, so option B is always correct.

Solution 5

No, size_t has absolutely no connection to "holding any integer value which you might expect it to be required to hold". Where did you get this?

size_t is supposed to be large enough to hold the byte-size of any continuous object in the given implementation. Conceptually, this is far less that "any integer value". The language does not guarantee that you are allowed to create objects that occupy the entire addressable storage, which means that size_t is conceptually not even enough to hold count of addressable bytes of memory.

If you wanted to tie "any integer value" to the memory size, then the appropriate type would be uintptr_t, which is conceptually larger than size_t. But I don't see any reason to tie "any integer value" to memory characteristics at all. E.g. even though uintptr_t is larger than size_t, it is not guaranteed to be large enough to hold the size of the largest file in your platform's file system.

The reason you can use size_t to iterate over std::vector's elements is that vector is internally based on an array. Arrays are continuous objects, which is why their sizes are covered by size_t. But once you take into consideration a non-contiguous container, like std::list, size_t is no longer guaranteed to be sufficient to measure or index such containers.

uint64_t can easier be greater than size_t. But it is quite possible that you might have to work with integer values that don't fit into uint64_t.

Share:
11,763
FreelanceConsultant
Author by

FreelanceConsultant

No longer available for hire for contract work Expertise include: Research (Any) Data Analysis, Signal Processing Mathematics C, C++ and Python Multi-thread, parallel and networked CUDA, OpenCL

Updated on June 06, 2022

Comments

  • FreelanceConsultant
    FreelanceConsultant about 2 years

    My understanding of size_t is that it will be large enough to hold any (integer) value which you might expect it to be required to hold. (Perhaps that is a poor explanation?)

    For example, if you were using something like a for loop to iterate over all elements in a vector, size_t would typically be 64 bits long (or at least on my system) in order that it can hold all possible return values from vector.size().

    Or at least, I think that's correct?

    Therefore, is there any reason to use A rather than B:

    A: for(uint64_t i = 0; i < v.size(); ++ i)

    B: for(size_t i = 0; i < v.size(); ++ i)

    If I'm wrong with my explanation or you have a better explanation, please feel free to edit.

    Edit: I should add that my understanding is that size_t behaves like a normal unsigned integer - perhaps that is not correct?

  • tmlen
    tmlen over 9 years
    std::malloc and std::allocator also use std::size_t.
  • Deduplicator
    Deduplicator over 9 years
    Even uintptr_t might be too small. As there's no limit for the values in OPs description...
  • AnT stands with Russia
    AnT stands with Russia over 9 years
    @tmlen: They do because they allocate continuous blocks of memory, i.e. they allocate arrays of bytes. For them it is perfectly appropriate to use size_t.
  • dtech
    dtech over 9 years
    should be "guaranteed TO be"
  • Nick
    Nick over 6 years
    No offence, but std::vector<T>::size() returns std::vector<T>::size_type
  • Deduplicator
    Deduplicator over 6 years
    Yes, and that comes from the allocator.