7

Is there any issue with using a C string as a map key?

std::map<const char*, int> imap;

The order of the elements in the map doesn't matter, so it's okay if they are ordered using std::less<const char*>.

I'm using Visual Studio and according to MSDN (Microsoft specific):

In some cases, identical string literals can be "pooled" to save space in the executable file. In string-literal pooling, the compiler causes all references to a particular string literal to point to the same location in memory, instead of having each reference point to a separate instance of the string literal.

It says that they are only pooled in some cases, so it seems like accessing the map elements using a string literal would be a bad idea:

//Could these be referring to different map elements?
int i = imap["hello"];
int j = imap["hello"];

Is it possible to overload operator== for const char* so that the actual C string and not the pointer values would be used to determine if the map elements are equal:

bool operator==(const char* a, const char* b)
{
    return strcmp(a, b) == 0 ? true : false;
}

Is it ever a good idea to use a C string as a map key?

user974967
  • 2,928
  • 10
  • 28
  • 45

3 Answers3

8

Is it possible to overload operator== for const char* so that the actual C string and not the pointer values would be used to determine if the map elements are equal

No it's not, and yes, it's not a good idea for exactly the reason pointed out in the question and because you don't need char*, you can use a std::string instead. (you can provide a custom compare function - as pointed out by simonc, but I'd advise against it)

//Could these be referring to different map elements?
int i = imap["hello"];
int j = imap["hello"];

Yes, and they can even refer to elements that don't exist yet, but they'll be created by operator[] and be value initialized. The same issue exists with assignment:

imap["hello"] = 0;
imap["hello"] = 1;

The map could now have 1 or 2 elements.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
7

You can provide a map with a custom comparitor which compares the C strings

std::map<const char*,YourType,CstrCmp>;

bool CstrCmp::operator()(const char* a, const char* b) const
{
    return strcmp(a, b) < 0;
}
Tara
  • 1,673
  • 22
  • 30
simonc
  • 41,632
  • 12
  • 85
  • 103
  • I know the comparitor is used to determine the position of elements in the map, but it is also used to determine if two map elements are equal? In other words, if you supply a comparitor, it will be used over operator== to determine if two map elements are equal? – user974967 Dec 13 '12 at 11:49
  • A map says that two elements are "equivalent" if neither is less than the other. So for example if your string comparison is case-insensitive, the map can contain "abc" or "ABC" but not both. – Alexander Chertov Dec 13 '12 at 11:51
  • 1
    @user974967 `operator==` is never used for anything in the map: it is always the supplied comparer, which defaults to `std::less`. The map needs one and only one criterion for it to work correctly. – Gorpik Dec 13 '12 at 12:06
1

First, in order to introduce ordering over map keys you need to define a "less-than" comparison. A map says that two elements are "equivalent" if neither is less than the other. It's a bad idea to use char* for map keys because you will need to do memory management somewhere outside the map.

In most realistic scenarios when you query a map your keys will not be literals.

On the other hand, if you maintain a pool of string literals yourself and assign an ID to every literal you could use those IDs for map keys.

To summarize, I wouldn't rely on Microsoft saying "In some cases literals may be pooled". If you fill the map with literals and if you query the map with literals as keys you might as well use enum for keys.

Alexander Chertov
  • 2,070
  • 13
  • 16