tags:

views:

1308

answers:

10

Why is it that in C++ containers, it returns a size_type rather than an int? If we're creating our own structures, should we also be encouraged to use size_type?

+1  A: 

ints are not guaranteed to be 4 bytes in the specification, so they are not reliable. Yes, size_type would be preferred over ints

Charles Ma
Are size_t's guaranteed to be any particular size?
MatrixFrog
Strangely enough they are only required to be able to represent values between 0 and 65,535. The relevant clause in the Standard is 7.18.3 in C99. The actual limitation is between 0 and SIZE_MAX as defined in <limits.h>
D.Shawley
+1  A: 

I assume you mean "size_t" -- this is a way of indicating an unsigned integer (an integer that can only be positive, never negative) -- it makes sense for containers' sizes since you can't have an array with a size of -7. I wouldn't say that you have to use size_t but it does indicate to others using your code "This number here is always positive." It also gives you a greater range of positive numbers, but that is likely to be unimportant unless you have some very big containers.

MatrixFrog
size_t and size_type (although they have commonly same value) are two different things.
eed3si9n
+3  A: 

A few reasons might be:

  • The type (size_t) can be defined as the largest unsigned integer on that platform. For example, it might be defined as a 32 bit integer or a 64 bit integer or something else altogether that's capable of storing unsigned values of a great length
  • To make it clear when reading a program that the value is a size and not just a "regular" int

If you're writing an app that's just for you and/or throwaway, you're probably fine to use a basic int. If you're writing a library or something substantial, size_t is probably a better way to go.

Dave
+1  A: 

C++ is a language that could be implemented on different hardware architectures and platforms. As time has gone by it has supported 16-, 32-, and 64-bit architecture, and likely others in the future. size_type and other type aliases are ways for libraries to insulate the programmers/code from implementation details.

Assuming the size_type uses 32 bits on 32-bit machines and 64 bits on 64-bit machines, the same source code likely would work better if you've used size_type where needed. In most cases you could assume it would be the same as unsigned int, but it's not guaranteed.

size_type is used to express capacities of STL containers like std::vector whereas size_t is used to express byte size of an object in C/C++.

eed3si9n
+1  A: 

All containers in the stl have various typedefs. For example, value_type is the element type, and size_type is the number stored type. In this way the containers are completely generic based on platform and implementation.

If you are creating your own containers, you should use size_type too. Typically this is done

typedef std::size_t size_type;

If you want a container's size, you should write

typedef vector<int> ints;
ints v;
v.push_back(4);
ints::size_type s = v.size();

What's nice is that if later you want to use a list, just change the typedef to

typedef list<int> ints;

And it will still work!

rlbond
+7  A: 

In general, size_t should be used whenever you are measuring the size of something. It is really strange that size_t is only required to represent between 0 and SIZE_MAX bytes and SIZE_MAX is only required to be 65,535...

The other interesting constraints from the C++ and C Standards are:

  • the return type of sizeof() is size_t and it is an unsigned integer
  • operator new() takes the number of bytes to allocate as a size_t parameter
  • size_t is defined in <cstddef>
  • SIZE_MAX is defined in <limits.h> in C99 but not mentioned in C++98?!
  • size_t is not included in the list of fundamental integer types so I have always assumed that size_t is a type alias for one of the fundamental types: char, short int, int, and long int.

If you are counting bytes, then you should definitely be using size_t. If you are counting the number of elements, then you should probably use size_t since this seems to be what C++ has been using. In any case, you don't want to use int - at the very least use unsigned long or unsigned long long if you are using TR1. Or... even better... typedef whatever you end up using to size_type or just include <cstddef> and use std::size_t.

D.Shawley
size_t is not only required to go up to 64k, it's also required to be able to represent the size of any object (in the C standard, I think, so maybe the C++ standard doesn't mention it). Pretty much any compiler is going to have to make it the same size as a pointer. Not quite as strange as it looks.
Steve Jessop
Yes, it is required to represent the size of any single object allocation in memory. It isn't required to represent the maximum number of objects, just the number of bytes consumed by the largest representable object. Comparing the range of size_t with addressable memory isn't really a valid comparison unless you can allocate the entire range of addressable memory in a single object.
D.Shawley
Hence "pretty much any compiler". Now that we mostly have unsegmented memory architectures, and a desire to mmap large files, and most compilers implement intptr_t (from C99) or similar, there's not much mileage in artificially limiting the size of an object to a smaller integer type than can span the address space. So that's why I don't think it's surprising that C++ implementations use size_t for size_type. The reason the 64k SIZE_MAX minimum is so low is probably just to support 16bit architectures: you'd not expect a 32bit+ compiler to actually do that.
Steve Jessop
A: 
void f1(size_t n) {
    if (n <= myVector.size()) { assert(false); }
    size_t n1 = n - myVector.size(); // bug! myVector.size() can be > n       
    do_stuff_n_times(n1);
}

void f2(int n) {
    int n1 = n - static_cast<int>(myVector.size());
    assert(n1 >= 0);
    do_stuff_n_times(n1);
}

f1() and f2() both have the same bug, but detecting the problem in f2() is easier. For more complex code, unsigned integer arithmetic bugs are not as easy to identify.

Personally I use signed int for all my sizes unless unsigned int should be used. I have never run into situation where my size won't fit into a 32 bit signed integer. I will probably use 64 bit signed integers before I use unsigned 32 bit integers.

The problem with using signed integers for size is a lot of static_cast from size_t to int in your code.

Shing Yip
A: 

size_t is unsigned, so even if they're both 32 bits it doesn't mean quite the same thing as an unqualified int. I'm not sure why they added the type, but on many platforms today sizeof (size_t) == sizeof (int) == sizeof (long), so which type you choose is up to you. Note that those relations aren't guaranteed by the standard and are rapidly becoming out of date as 64 bit platforms move in.

For your own code, if you need to represent something that is a "size" conceptually and can never be negative, size_t would be a fine choice.

Dan Olson
A: 

About size_t

A: 

Some of the answers are more complicated than necessary. A size_t is an unsigned integer type that is guaranteed to be big enough to store the size in bytes of any object in memory. In practice, it is always the same size as the pointer type. On 32 bit systems it is 32 bits. On 64 bit systems it is 64 bits.

Andy Ross