4

I'm developing game. I store my game-objects in this map:

std::map<std::string, Object*> mObjects;

std::string is a key/name of object to find further in code. It's very easy to point some objects, like: mObjects["Player"] = .... But I'm afraid it's to slow due to allocation of std::string in each searching in that map. So I decided to use int as key in that map.

The first question: is that really would be faster?

And the second, I don't want to remove my current type of objects accesing, so I found the way: store crc string calculating as key. For example:

Object *getObject(std::string &key)
{
   int checksum = GetCrc32(key);
   return mObjects[checksum];
}

Object *temp = getOject("Player");

Or this is bad idea? For calculating crc I would use boost::crc. Or this is bad idea and calculating of checksum is much slower than searching in map with key type std::string?

Max Frai
  • 61,946
  • 78
  • 197
  • 306
  • 1
    If you're using a string literal `"Player"` in your real code, then it would probably make more sense to have an `Object *player` variable somewhere to point to the player, and only use the `mObjects` map to look up objects whose key/name is unknown at compile time. – Steve Jessop Apr 08 '11 at 10:17

4 Answers4

6

Calculating a CRC is sure to be slower than any single comparison of strings, but you can expect to do about log2N comparisons before finding the key (e.g. 10 comparisons for 1000 keys), so it depends on the size of your map. CRC can also result in collisions, so it's error prone (you could detect collisions relatively easily detect, and possibly even handle them to get correct results anyway, but you'd have to be very careful to get it right).

You could try an unordered_map<> (possibly called hash_map) if your C++ environment provides one - it may or may not be faster but won't be sorted if you iterate. Hash maps are yet another compromise:

  • the time to hash is probably similar to the time for your CRC, but
  • afterwards they can often seek directly to the value instead of having to do the binary-tree walk in a normal map
  • they prebundle a bit of logic to handle collisions.

(Silly point, but if you can continue to use ints and they can be contiguous, then do remember that you can replace the lookup with an array which is much faster. If the integers aren't actually contiguous, but aren't particularly sparse, you could use a sparse index e.g. array of 10000 short ints that are indices into 1000 packed records).

Bottom line is if you care enough to ask, you should implement these alternatives and benchmark them to see which really works best with your particular application, and if they really make any tangible difference. Any of them can be best in certain circumstances, and if you don't care enough to seriously compare them then it clearly means any of them will do.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
3

For the actual performance you need to profile the code and see it. But I would be tempted to use hash_map. Although its not part of the C++ standard library most of the popular implentations provide it. It provides very fast lookup.

Asha
  • 11,002
  • 6
  • 44
  • 66
3

The first question: is that really would be faster?

yes - you're comparing an int several times, vs comparing a potentially large map of strings of arbitrary length several times.

checksum: Or this is bad idea?

it's definitely not guaranteed to be unique. it's a bug waiting to bite.

what i'd do:

use multiple collections and embrace type safety:

// perhaps this simplifies things enough that t_player_id can be an int?
std::map<t_player_id, t_player> d_players;
std::map<t_ghoul_id, t_ghoul> d_ghouls;
std::map<t_carrot_id, t_carrot> d_carrots;

faster searches, more type safety. smaller collections. smaller allocations/resizes.... and on and on... if your app is very trivial, then this won't matter. use this approach going forward, and adjust after profiling/as needed for existing programs.

good luck

justin
  • 104,054
  • 14
  • 179
  • 226
  • Thanks ;) My application isn't small. But the map could store not more than 1000 objects. I'll think about your ideas. – Max Frai Apr 08 '11 at 10:05
  • you're welcome. comparing that many strings will cover a lot of memory (read: accesses will be very slow). string has some internal optimizations. for example, the length can quickly identify strings which definitely don't match. but still, that's a lot of memory to span if it needs to be fast. so it really depends on how frequent you need to access the container's objects. if you need this layout, create a custom type of a constant string pool. then it's as easy as pointer comparisons and requires 0 allocations during play (assuming you stash the pointer to the pooled allocation and reuse it) – justin Apr 08 '11 at 10:11
1

If you really want to know you have to profile your code and see how long does the function getObject take. Personally I use valgrind and KCachegrind to profile and render data on UNIX system.

I think using id would be faster. It's faster to compare int than string so...

Maxence SCHMITT
  • 609
  • 4
  • 12