3

How do you get the number of elements in a std::map as an unsigned long?

Assuming you have an object like this:

std::map<unsigned long, someClass *> myNightmare;

I have been trying to figure out how to get its number of elements. You see, I need this number as an unsigned long, and it doesn't seem correct to just do this:

unsigned long count = myNightmare.size();

So how should you get the number of elements as an unsigned long?

woolstar
  • 5,063
  • 20
  • 31
Alexandru
  • 12,264
  • 17
  • 113
  • 208
  • 1
    It's right there: `unsigned long count = myNightmare.size();` Why doesn't that feel correct to you? – jrok Jan 23 '14 at 18:22
  • 1
    If you want to be explicit, `unsigned long count = static_cast(myNightmare.size());`? And to be super-careful, you could always cast back to `std::map::size_type` and verify that the value did not change. – JAB Jan 23 '14 at 18:22
  • @jrok Well, size() returns a size_type, not an unsigned long, right? – Alexandru Jan 23 '14 at 18:23
  • 1
    @Alexandru `size_type` is a typedef for some unsigned integral type (it's required to be). It could easily be `unsigned long`. – jrok Jan 23 '14 at 18:28
  • #ifndef __SIZE_TYPE__ #define __SIZE_TYPE__ **long unsigned int** #endif #if !(defined (__GNUG__) && defined (size_t)) typedef __SIZE_TYPE__ size_t; – Dabo Jan 23 '14 at 18:29
  • 1
    Regardless of what the `size_type` actually is, the size of a map whose key type is `unsigned long` is guaranteed to fit in an `unsigned long`, because that's the maximum number of distinct keys possible. So the conversion is safe. `multimap` would (in principle) be a different matter, you might want a range check before assigning the value to `unsigned long`. – Steve Jessop Jan 23 '14 at 18:31
  • @SteveJessop Ah, okay. That really did the trick in opening my eyes. Thanks, Steve. That's what I was pretty much concerned with but I just couldn't quite communicate it right. – Alexandru Jan 23 '14 at 18:32
  • 2
    @SteveJessop: If a map holds every single possible `unsigned long` value, then its size is 1 greater than the max value an `unsigned long` can hold. – Benjamin Lindley Jan 23 '14 at 18:39
  • Benjamin has a point. Wouldn't you want to still range-check it in this case, then? – Alexandru Jan 23 '14 at 18:41
  • No, wait...but its keyed off by the unsigned long, so, actually shouldn't its max size be the size of the unsigned long's maximum? Why +1? – Alexandru Jan 23 '14 at 18:42
  • Map starts at 0, right? – Alexandru Jan 23 '14 at 18:42
  • 1
    @Alexandru: Let's assume, for simplicity sake, that unsigned long is 4 bits. Its min value is 0, and its max value is 15. There are 16 possible values, 0 through 15, but the unsigned long can only hold up to the value 15. So it cannot store the maximum size of a map with `unsigned long` as a key. – Benjamin Lindley Jan 23 '14 at 18:47
  • Oops yes, Benjamin is right of course. You could use `boost::numeric_cast` to do a checking conversion, or check yourself for the one special case. The realistic scenario where you could create a map containing all possible keys is when `unsigned long` is only 32 bits on a 64 bit platform, such as Windows. – Steve Jessop Jan 23 '14 at 18:47
  • Well, the answers below are somewhat incorrect casts then, right? – Alexandru Jan 23 '14 at 19:03
  • 1
    No, the answers aren't incorrect. If you want to store the result in an `unsigned long`, that's what you do. In the extremely unlikely event that you use up every single possible key, the value will be wrong. But you can't store the correct value anyway. If you want to throw in a check beforehand, that's up to you, but you still won't be able to store the value in an `unsigned_long`. – Benjamin Lindley Jan 23 '14 at 19:38
  • @BenjaminLindley You're a hero. How about you answer this one so that I can mark it as the correct answer? You can include this explanation, because to me, the correct answer is that casting this value to an unsigned long is actually not the best way to go about trying to get the number of elements in my current map. – Alexandru Jan 23 '14 at 20:02

2 Answers2

7

Use static cast.

long unsigned mySize = static_cast<long unsigned>(myNightmare.size());
poljpocket
  • 318
  • 1
  • 10
2

To be really portable and correct you should use the standard std::size_t or more precisely std::map<unsigned long, someClass*>::size_type.

The latter is the type returned from std::map::size, but it does not, generally, differ from the more generic std::size_t.

If you really want to still use long unsigned, then your line:

unsigned long count = myNightmare.size();

will perform an implicit conversion for you, already.

Shoe
  • 74,840
  • 36
  • 166
  • 272