std :: unordered_map一直导致错误,这是一个错误吗?

时间:2016-03-14 01:41:18

标签: 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而不是insert,尝试使用std :: make_pair,但所有组合都无济于事。

现在,我错过了一些明显错误的东西,或者某处有错误?

更新

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

main.cc

#include "stringid.h"

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

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

stringid.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

string.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()上得到错误。

1 个答案:

答案 0 :(得分:2)

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

这是一个错误。哈希不是唯一的。

你想要做的是用一把钥匙键入哈希表!

表哈希是一个实现细节,你不应该在外面看到。

解决这个问题的最简单方法是使用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匹配,即使原始指针不同。

你可以提高效率(例如使用一些带有自定义键比较器的设置)