什么可以使 std::map 找不到其中一个键?

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

我有一个 std::map 将 const char* 键与 int 值关联:

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

我用三个键初始化它,然后检查它是否能找到它:

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

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

没有打印任何内容。从这里看,一切正常。

但后来在我的代码中,在不对这张地图做任何改动的情况下,我再次尝试找到一个密钥:

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

但是at函数抛出一个std::out_of_range异常,这意味着它找不到元素。 myMap.find("zero") 认为相同,因为它 returns 是地图末尾的迭代器。


但最令人毛骨悚然的部分是关键确实在地图中,如果就在调用 at 函数之前,我像这样打印地图的内容:

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

输出符合预期:

zero
first
second


这怎么可能?我不使用任何 beta 测试库或任何应该不稳定的东西。

你有一个字符指针映射,而不是字符串。地图查找基于指针值(地址)而不是所指向的值。在第一种情况下,在映射中找到 "zero" 的地方,您的编译器已经执行了一些字符串合并,并且正在为两个相同的字符串使用一个字符数组。这不是语言所要求的,而是一种常见的优化。在第二种情况下,当没有找到字符串时,这个合并还没有完成(可能你这里的代码在不同的源模块中),所以映射中使用的地址与插入的地址不同,然后找不到.

要解决此问题,请在地图中存储 std::string 个对象,或者在地图声明中指定比较以根据字符串而不是地址进行排序。

映射的关键是 char *。所以 map 比较函数将尝试比较原始指针值而不是 c 风格的 char 字符串等价性检查。所以声明以 std::string 为键的地图。

如果您不想处理 std::string 并且仍然想要具有改进的时间复杂度的相同功能,复杂的数据结构是 trie。查看一些实现,例如 Judy Array.