Aracthor
Aracthor

Reputation: 5907

What can bring a std::map to not find one of its keys?

I have a std::map associating const char* keys with int values:

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

I initialize it with three keys, then check if it can find it:

myMap["zero"] = 0;
myMap["first"] = 1;
myMap["second"] = 2;

if (myMap.at("zero") != 0)
{
    std::cerr << "We have a problem here..." << std::endl;
}

And nothing is printed. From here, everything looks ok.

But later in my code, without any alteration of this map, I try to find again a key:

int value = myMap.at("zero");

But the at function throws an std::out_of_range exception, which means it cannot find the element. myMap.find("zero") thinks the same, because it returns an iterator on the end of the map.


But the creepiest part is that the key is really in the map, if just before the call to the at function, I print the content of the map like this:

for (auto it = myMap.begin(); it != myMap.end(); it++)
{
    std::cout << (*it).first << std::endl;
}

The output is as expected:

zero
first
second


How is it even possible? I don't use any beta-test library or anything supposed to be unstable.

Upvotes: 0

Views: 231

Answers (2)

rahul.deshmukhpatil
rahul.deshmukhpatil

Reputation: 997

key to map is char * . So map comparison function will try to compare raw pointer values and not the c style char string equivalence check. So declare the map having std::string as the key.

if you do not want to deal with the std::string and still want the same functionality with improved time complexity, sophisticated data structure is trie. Look at some implementations like Judy Array.

Upvotes: 1

1201ProgramAlarm
1201ProgramAlarm

Reputation: 32732

You have a map of pointers to characters, not strings. The map lookup is based on the pointer value (address) and not the value of what's pointed at. In the first case, where "zero" is found in the map, you compiler has performed some string merging and is using one array of characters for both identical strings. This is not required by the language but is a common optimization. In the second case, when the string is not found, this merging has not been done (possibly your code here is in a different source module), so the address being used in the map is different from what was inserted and is then not found.

To fix this either store std::string objects in the map, or specify a comparison in your map declaration to order based on the strings and not the addresses.

Upvotes: 8

Related Questions