[ACCEPTED]-C++ for-loop - size_type vs. size_t-size-type

Accepted answer
Score: 18

The C++ Standard says,

 size_type  |  unsigned integral type  |  a type that can represent the size of the largest object in the
allocation model

Then it adds,

Implementations 8 of containers described in this International Standard 7 are permitted to assume that their Allocator 6 template parameter meets the following 5 two additional requirements beyond those 4 in Table 32.

  • The typedef members pointer, const_pointer, size_type, and difference_type are required to be T*,T const*, size_t, and ptrdiff_t, respectively

So most likely, size_type is a typedef 3 of size_t.

And the Standard really defines it as,

template <class T> 
class allocator 
{
   public:
       typedef size_t size_type;
       //.......
};

So 2 the most important points to be noted are 1 :

  • size_type is unsigned integral, while int is not necessarily unsigned. :-)
  • it can represent the largest index, because it's unsigned.
Score: 16

Yes you can use int, but only the type vector<int>::size_type guarantees 10 that its type can be used to index all vector 9 elements.

It may or may not be the same size 8 as int. Eg, when compiling for 64-bit Windows, int is 7 32-bit wide, whereas vector<int>::size_type will be 64-bit wide.

Instead 6 of using the rather verbose vector<int>::size_type, you could 5 use std::size_t, as the former is a typedef for the 4 latter. However, if you ever happen to change 3 the container type, then its size_type maybe a different 2 type, and you may have to modify your code 1 if it uses std::size_t.

Score: 9

vector<int>::size_type is a type that is guaranteed to hold the 31 size of the biggest vector you may have, and thus 30 it's guaranteed to let you index all the 29 elements of the vector (since indexes go from 28 0 to size-1); it is the type used for indexes 27 and sizes in all the vector methods.

If you have 26 very big arrays this may be actually relevant, since 25 other integer types may overflow (and if 24 they are signed types things can get quite strange); even 23 if you won't ever get to arrays so big that 22 this may matter, it's fundamentally a code 21 cleanliness thing; moreover, your ix has the 20 same type of ivec.size(), so you don't get warnings 19 for comparing signed and unsigned integers.

Background: vector<T>::size_type is 18 usually a typedef for size_t (I read somewhere that actually 17 the standard implicitly imposes it to be size_t - EDIT: it's 16 not implicit at all, see @Nawaz's answer), which, in 15 turn, is the return type of the sizeof operator. This 14 implicitly says that it can hold the size 13 for the biggest object usable in a C++ application, so 12 it is surely (just) big enough to index 11 arrays of any type.

Actually, I use size_t (defined 10 in <cstddef>) as index also for C-style arrays, and 9 I think it's good practice for exactly the 8 same reasons.


By the way, you may also forget 7 of the type used for indexes altogether 6 and just go with iterators:

for (vector<int>::iterator it = ivec.begin(); it != ivec.end(); ++it)
    *it = 0;

or with iterators+<algorithm>:

std::fill(ivec.begin(), ivec.end(), 0);

These 5 two options work whatever container ivec is, so 4 you don't have to change anything in the 3 code if you decide to change container type.

With 2 vector you can also use the assign method (as suggested 1 in some other answer):

ivec.assign(ivec.size(), 0);
Score: 3

You should not use intbecause vector<int>::size_type is an unsigned 11 type, that is, vector indexes its elements 10 with an unsigned type. int however is a signed 9 type and mixing signed and unsigned types 8 can lead to weird problems. (Although it 7 would not be a problem for small n in your 6 example.)

Note that I think it's clearer 5 to just use size_t (as opposed to T::size_type) - less 4 typing and should work on all implementations.

Note 3 also that the for loop you posted:

for(size_t ix=0; ix != ivec.size(); ++ix) ...

would 2 be better written as:

for(size_t i=0, e=ivec.size(); i!=e; ++ix) ...

-- no need to call 1 size() every iteration.

More Related questions