Я пробовал различные реализации в Visual C++ 16.0 (тот, который поставляется с Visual Studio 2010), и я получаю всевозможные ошибки с помощью std::unordered_map
Например
CKey key = pszName;
auto it = m_Records.find(key);
if (it != m_Records.end())
{
// we replace existing item (so delete old)
delete it->second;
it->second = pRecord;
}
else
{
const size_t sz = m_Records.size();
m_Records.insert(std::make_pair(key, pRecord));
const size_t sz2 = m_Records.size();
assert((sz + 1) == sz2); // this assertion fails! wtf!
}
m_Records
- это экземпляр std :: unordered_map. Поэтому я переключился на boost::unordered_map
1.48. Теперь это работает, но у меня другая проблема в другом месте. Тот же код выше, хотя один и тот же ключ продолжает вставляться дважды или более. Как моя карта не может управлять простейшими вещами и содержать только одну запись на ключ?
Я проверял трижды на функцию хеша и функцию сравнения. Я не верю, что они виноваты здесь.
Что я делаю не так?
Тип m_Records
- либо boost::unordered_map<CKey, CRecord*>
либо std::unordered_map<CKey, CRecord*>
.
CKey
определяется как таковой:
struct CKey
{
const wchar_t* m_Str;
int m_Len;
CKey(const wchar_t* s)
: m_Str(s)
, m_Len(s ? (int)wcslen(s) : 0)
{
}
size_t hash() const
{
if (this->m_Len > 0)
{
char temp[16];
memset(temp, 0, sizeof(temp));
MurmurHash3_x64_128(this->m_Str, (int)sizeof(wchar_t) * this->m_Len, 0, temp);
size_t hash = *(size_t*)temp;
return hash;
}
return 0;
}
bool operator==(const CKey& other) const
{
if ((this->m_Len > 0) & (this->m_Len == other.m_Len))
{
return (wcscmp(this->m_Str, other.m_Str) == 0);
}
// otherwise, they are only equal if they are both empty
return (this->m_Len == 0) & (other.m_Len == 0);
}
};
namespace boost
{
template <>
struct hash<CKey>
{
size_t operator()(const CKey& k) const
{
return k.hash();
}
};
}
namespace std
{
template <>
struct equal_to<CKey>
{
bool operator()(const CKey& x, const CKey& y) const
{
return (x == y);
}
};
}
Оказалось, что проблема была простой проблемой общей памяти. Я неосознанно не считал, что память, которую я использовал для вставки элемента, была получена из временной переменной. Несмотря на то, что все было сохранено в памяти кучи, фактическое значение ключа (а не хеш или позиция ковша) изменилось с позиции на запись. Это, в свою очередь, привело к вышеуказанным непоследовательным и нелогичным операциям.
Выученный ученый, когда характер проблемы нелогичен, причина проблемы, вероятно, будет схожей по своему характеру. Я просто изменил объявление const char* m_Str
в CKey
на std::wstring m_Str
и он это сделал.
Исправление сделало структуру CKey
значительно меньшей, что было приятно. Подстановка моей первоначальной реализации для этого работала просто отлично.
struct CKey
{
std::wstring m_Str;
CKey(const wchar_t* s)
: m_Str(s)
{
}
size_t hash() const
{
if (!this->m_Str.empty())
{
char temp[16];
memset(temp, 0, sizeof(temp));
MurmurHash3_x64_128(this->m_Str.c_str(), (int)sizeof(wchar_t) * (int)this->m_Str.size(), 0, temp);
size_t hash = *(size_t*)temp;
return hash;
}
return 0;
}
bool operator==(const CKey& other) const
{
return this->m_Str.compare(other.m_Str) == 0;
}
};
boost
?