c++ - std::unordered_map 不断导致错误,这是一个错误吗?

标签 c++ c++11 std unordered-map

所以我有这个用于散列内部字符串的函数,但是当我尝试运行它时,Visual Studio 2015 给我一个调试断言失败!错误:

Program: C:\WINDOWS\SYSTEM32\MSVCP140D.dll
File: c:\program files (x86)\microsoft visual studio 14.0\vc\include\vector
Line: 1232

Expression: vector subscript out of range

现在第一次调用 InternalString 时我得到这个错误,它在 gStringIdTable.find(sid) 行中断。

static std::unordered_map<StringId, const char*> gStringIdTable;

StringId InternalString(const char* string) {
    StringId sid = std::hash<std::string>()(string);

    std::unordered_map<StringId, const char*>::iterator it = gStringIdTable.find(sid);

    if (it == gStringIdTable.end()) {
        gStringIdTable.insert({sid, string});
    }

    return sid;
}

我想这可能是我初始化迭代器的方式有问题,所以我想我会试试这个:

if (gStringIdTable.find(sid) == gStringIdTable.end()) {
    gStringIdTable.insert({sid, string});
}

但这给了我同样的错误。然后我想这可能与在 unordered_map 填充任何东西之前进行查找有关,所以我尝试只在函数中插入。但这也给了我同样的错误。我尝试将 const char* 转换为 std::string,然后只处理位于 this answer's 处的 unordered_map 中的字符串。建议,但得到了同样的错误。我尝试使用 emplace 而不是插入,尝试使用 std::make_pair,但所有组合都无济于事。

现在,我是否漏掉了明显错误的东西,或者某处存在错误?

更新

好的,这是一个编译版本,但我仍然遇到错误。我在 visual studio 2015 中启动了一个空的 c++ 项目并添加了这 3 个文件以匹配它当前在我的项目中的实现方式:

主.cc

#include "stringid.h"

const static mynamespace::StringId kSidOne = mynamespace::InternalString("One");

int main(int argc, char *argv[]) {
    return 0;
}

字符串id.cc

#include "stringid.h"
#include <string>
#include <unordered_map>

namespace mynamespace {

static std::unordered_map<StringId, std::string*> gStringIdTable;

StringId InternalString(const char* string) {
    StringId sid = std::hash<std::string>()(string);

    if (gStringIdTable.find(sid) == gStringIdTable.end()) {
        gStringIdTable.emplace(sid, new std::string(string));
    }

    return sid;
}

} // mynamespace

字符串.h

#ifndef STRINGID_H_
#define STRINGID_H_

namespace mynamespace {

typedef unsigned int StringId;
StringId InternalString(const char* string);

} // mynamespace

#endif // STRINGID_H_

我还对这些函数进行了一些调试,看看我是否能找出问题出在哪里,看起来当 find 函数获取相关存储桶时它返回 null 或 0,然后 _Begin 函数抛出错误,因为大小等于零。

小更新

我也试过用 gcc 编译。它编译得很好,但我仍然在 find() 上遇到错误。

最佳答案

您正在使用...哈希表来键入哈希表。

这是一个错误。散列不是唯一的。

你想要做的是用...键来键入哈希表!

表如何散列是一个实现细节,您不应该在外面看到。

解决此问题的最简单方法是,例如使用 std::unordered_set<std::string> .

Live On Coliru

#include <unordered_set>

const char* InternalString(const char* string) {
    static std::unordered_set<std::string> s_table;
    std::unordered_set<std::string>::iterator it = s_table.find(string);

    return (it != s_table.end())? it->c_str() : s_table.insert(string).first->c_str();
}

#include <cassert>

int main() {
    auto a = InternalString("HelloWorld" + 5);
    auto b = InternalString("World");

    assert(a == b);
}

断言验证正常,因为 WorldWorld匹配,即使原始指针不同。

你可以使这更有效(例如通过使用一些带有自定义键比较器的集合)

关于c++ - std::unordered_map 不断导致错误,这是一个错误吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35978221/

相关文章:

c++ - 带有 memset_s 分配器的 std::vector

c++ - std:find()用于排序与未排序

c++ - 模数中的线性组合 C++

c++ - 如何让 tr1::array 分配对齐内存?

c++ - 并行搜索不同的值?

c++ - 使用 std::fstream 重新打开后文件被清除

c++ - 未捕获 vector 的异常

c++ - 通过打印机 C++ 打印

c++ - 大小为 1 的 char 数组和 strcat 的问题

c++ - 优雅地从指针初始化 std::array 到缓冲区?