tags:

views:

678

answers:

7

It seems safe to cast the result of my vector's size() function to an unsigned int. How can I tell for sure, though? My documentation isn't clear about how size_type is defined.

+4  A: 

According to the standard, you cannot be sure. The exact type depends on your machine. You can look at the definition in your compiler's header implementations, though.

Konrad Rudolph
I tried looking in my headers. Having followed quite a maze of generic definitions, I came to a dead end in a file called xmemory, where the type size_t is mentioned. According to my IDE, size_t isn't defined anywhere!
Tommy Herbert
Yup - reading library headers (especially template-based ones) can be a real pain.
Michael Burr
At least on gcc, the header which actually defines size_t (stddef.h) is buried somewhere else, far from the usual includes (/usr/lib/gcc/.../include instead of /usr/include).
CesarB
size_t is a standard C typedef. Look in cstddef, which will probably lead you to stddef.h ( http://www.cplusplus.com/reference/clibrary/cstring/size_t.html ). Truth is, like NULL, most programmers I know don't include cstddef before using size_t.Honestly, size_t will probably be an unsigned int.
Max Lybbert
In general, you should be using size_t where you would be tempted to use unsigned int. For both types, you can not be sure how many bits they contain, but in size_t's case you *can* be sure it is large enough to measure the size of things in memory.
ejgottl
The question is why would you want to?
Martin York
@Martin: Why would you want to what? Determine if an int can hold a size_type? If that's what you're asking, then as JF has mentioned a couple times it might be because you're passing it to an API or something you have no control over that wants an int.
Michael Burr
A: 

As long as you're sure that an unsigned int on your system will be large enough to hold the number of items you'll have in the vector you should be safe ;-)

J Francis
But that makes the code non portal. The whole point is tow rite good code.
Martin York
"as long as .. unsigned int .. will be large enough". That's what Tommy is trying to figure out. This is a non answer.
Aaron
Exactly! Whenever you cast you're overriding the type system, so you need to know what you're doing.
J Francis
@Aaron: I think you misunderstand JF's answer. He points out that it's safe as long as the actual runtime size of the vector is no greater than UINT_MAX. This is a weaker condition than that the width of the size_type is no greater than the width of unsigned int.
Steve Jessop
+3  A: 

I can't imagine that it wouldn't be safe on a 32-bit system, but 64-bit could be a problem (since ints remain 32 bit). To be safe, why not just declare your variable to be vector<MyType>::size_type instead of unsigned int?

Mark Ransom
That's what I've done, but I'm still curious about how one looks up information on STL.
Tommy Herbert
@Tommy : You already have all the information you need. The cast is not safe, you should be using "vector<MyType>::size_type" instead. or size_t. If you're only _curious_ what it is, ask the compiler: cout << typeid(size_t).name() << "\n"; // if you ask nicely, it might tell you.
Aaron
A: 

I'm not sure how well this will work because I'm just thinking off the top of my head, but a compile-time assertion (such as BOOST_STATIC_ASSERT() or see http://stackoverflow.com/questions/174356/ways-to-assert-expressions-at-build-time-in-c) might help. Something like:

BOOST_STATIC_ASSERT( sizeof( unsigned int) >= sizeof( size_type));
Michael Burr
But why. Assuming a type works here will not help when posrting the code.
Martin York
Maybe I'm misunderstanding something - if the compiler can verify that whatever type you want the size to get into is at least as big as the type you're gettingfrom size(), doesn't that answer the OP's question? Even if it doesn't fix the problem automatically
Michael Burr
Note that I assumeed that the OP wants to cast size_type to int because he's passing the result of size() to a function/method/structure/whatever that wants an int and is not under his control.
Michael Burr
A: 

It should always be safe to cast it to size_t. unsigned int isn't enough on most 64-bit systems, and even unsigned long isn't enough on Windows (which uses the LLP64 model instead of the LP64 model most Unix-like systems use).

CesarB
+7  A: 

Do not assume the type of the container size (or anything else typed inside).

Today?

The best solution for now is to use:

std::vector<T>::size_type

Where T is your type. For example:

std::vector<std::string>::size_type i ;
std::vector<int>::size_type j ;
std::vector<std::vector<double> >::size_type k ;

(Using a typedef could help make this better to read)

The same goes for iterators, and all other types "inside" STL containers.

After C++0x?

When the compiler will be able to find the type of the variable, you'll be able to use the auto keyword. For example:

void doSomething(const std::vector<double> & p_aData)
{
    std::vector<double>::size_type i = p_aData.size() ; // Old/Current way
    auto j = p_aData.size() ; // New C++0x way
}

Edit: Question from JF

What if he needs to pass the size of the container to some existing code that uses, say, an unsigned int? – JF

This is a problem common to the use of the STL: You cannot do it without some work.

The first solution is to design the code to always use the STL type. For example:

typedef std::vector<int>::size_type VIntSize ;

VIntSize getIndexOfSomeItem(const std::vector<int> p_aInt)
{
   return /* the found value, or some kind of std::npos */
}

The second is to make the conversion yourself, using either a static_cast, using a function that will assert if the value goes out of bounds of the destination type (sometimes, I see code using "char" because, "you know, the index will never go beyond 256" [I quote from memory]).

I believe this could be a full question in itself.

paercebal
What if he needs to pass the size of the container to some existing code that uses, say, an unsigned int?
J Francis
Good remark. I'll complete the answer
paercebal
In practice (and when using standard containers), size_type can be replaced by size_t. Here's a discussion about this:http://www.velocityreviews.com/forums/t281965-sizet-and-sizetype.html
vividos
+1  A: 

The C++ standard only states that *size_t* is found in <cstddef>, which puts the identifiers in <stddef.h>. My copy of Harbison & Steele places the minimum and maximum values for *size_t* in <stdint.h>. That should give you a notion of how big your recipient variable needs to be for your platform.

Your best bet is to stick with integer types that are large enough to hold a pointer on your platform. In C99, that'd be *intptr_t* and *uintptr_t*, also officially located in <stdint.h>.

Don Wakefield