2016-03-14 30 views
0

所以我有散列內部字符串的這個函數,但是當我嘗試運行它時,Visual Studio 2015給了我一個Debug Assertion Failed!錯誤:std :: unordered_map不斷導致錯誤,這是一個錯誤?

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_ 

我也做了一些調試功能,看看我是否可以弄清楚e問題來自於,它看起來像find函數抓取相關的桶時它返回null或0,然後_Begin函數拋出錯誤,因爲大小等於零。

小更新

我也試着用gcc編譯。它編譯好,但我仍然在find()上發生錯誤。

+1

我試圖重現該問題,並失敗。它對我來說運行得很好。請提供[mcve](http://stackoverflow.com/help/mcve),而不是僅提供一些片段。 – Rumburak

+0

@Rumburak已添加。 – jrdnbnnll

+0

聽起來像靜態初始化命令失敗。特別是'gStringIdTable'不保證在調用'InternalString'來初始化'kSidOne'的地方正確初始化。 –

回答

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); 
} 

斷言驗證OK,既然WorldWorld比賽,即使原始指針是不同的。

您可以使這個更有效率(例如通過使用一些與自定義鍵比較器集)

+0

散列只是返回一個整數,我在其他代碼中使用,所以我不必比較字符串,只需比較整數。我不能使用哈希函數產生的整數作爲關鍵字? – jrdnbnnll

+3

除非您不關心字符串與密鑰的唯一鍵或1對1映射關係。 – sehe

+0

添加了一些有用的(希望)的例子。如果你想要比較這個舊的答案:https://stackoverflow.com/a/20961180/85371 – sehe