【问题标题】:What can bring a std::map to not find one of its keys?什么会使 std::map 找不到它的一个键?
【发布时间】:2015-12-09 06:52:41
【问题描述】:

我有一个 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") 也这么认为,因为它在映射的末尾返回一个迭代器。


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

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

输出如预期:


第一
第二个


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

【问题讨论】:

  • 指向相同字符串字面量的指针是否保证具有相同的地址?
  • 我有一个 std::map 将 const char 键与 int 值关联:* -- 如果您希望键是字符串,请使用字符串:std::map&lt;std::string, int&gt; .

标签: c++ c++11 dictionary std


【解决方案1】:

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

要解决这个问题,要么在映射中存储 std::string 对象,要么在映射声明中指定一个比较,以根据字符串而不是地址进行排序。

【讨论】:

  • 感觉自己好蠢...忘记了std::map内部使用了操作符,还以为用了strcmp...
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 2010-12-11
    • 2016-01-01
    • 1970-01-01
    • 2010-11-09
    • 2010-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多