读取 unordered_multiset 导致崩溃

Reading from unordered_multiset results in crash

在重构一些旧代码时,内部 开发的繁琐多级地图被 std::undordered_multiset 取代。

多级地图类似于 [string_key1,string_val]。应用复杂算法从 string_val 派生密钥,结果在地图中存储了重复的 string_val,但密钥不同。

最终在应用程序的某个点迭代多级映射以获得 string_val 及其出现次数。

它替换的是 std::unordered_multilevelset 并且 string_val 只是插入其中。这似乎比使用 std::map<std::string,int> 并为每次插入检查-检索-更新计数器要简单得多。

我想做的是检索其插入元素的出现次数,但我事先没有密钥。所以我遍历了桶,但我的程序在创建字符串时崩溃了。

// hash map declaration
std::unordered_multiset<std::string> clevel;

// get element and occurences
for (size_t cbucket = clevel->bucket_count() - 1; cbucket != 0; --cbucket)
{
        std::string cmsg(*clevel->begin(cbucket));
        cmsg += t_str("times=") + \
                std::to_string(clevel->bucket_size(cbucket));
}

我不明白这里发生了什么,试图调试它但我不知何故堆栈(溢出?):)。程序在 std::string cmsg(*it);

时崩溃

您应该考虑 multiset 作为哈希表的实际工作方式。例如阅读这个 introduction 你应该注意到哈希映射实际上预先分配了它们的内部桶,并且桶的数量得到了优化。

因此,如果您插入元素 "hello" ,您可能会得到许多已创建的存储桶,但只有对应于 hash("hello") 的存储桶实际上有一个您可以取消引用的元素。其余的将被视为无效。

将迭代器取消引用到每个存储桶的开头会导致 SEGV,这就是您的情况。

要补救这种情况,您应该每次检查开始是否超过结束。

for (size_t cbucket = clevel->bucket_count() - 1; cbucket != 0; --cbucket)
{
    auto it = clevel->begin(cbucket);
    if (it != clevel->end(cbucket))
    {
        std::string cmsg(*it);
        cmsg += t_str("times=") + \
                std::to_string(clevel->bucket_size(cbucket));
    }
}