unordered_map не работает

0

Я пробовал различные реализации в 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);
  }
};
}
  • 1
    Что говорит отладчик, когда утверждение не выполняется, интересен ли ключ вообще? Могут ли ключи быть видоизменены во время нахождения на карте? (т. е. содержат ли они указатели на ресурсы, на которые другие ссылаются?) Можете ли вы создать MCVE? Какая версия boost ?
  • 0
    Это все однопоточное, без параллелизма, поэтому я не вижу, как что-то изменится, пока происходит вставка или какая-либо операция с картой.
Показать ещё 2 комментария
Теги:
boost
visual-studio-2010
c++-standard-library

1 ответ

3

Оказалось, что проблема была простой проблемой общей памяти. Я неосознанно не считал, что память, которую я использовал для вставки элемента, была получена из временной переменной. Несмотря на то, что все было сохранено в памяти кучи, фактическое значение ключа (а не хеш или позиция ковша) изменилось с позиции на запись. Это, в свою очередь, привело к вышеуказанным непоследовательным и нелогичным операциям.

Выученный ученый, когда характер проблемы нелогичен, причина проблемы, вероятно, будет схожей по своему характеру. Я просто изменил объявление 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;
  }
};
  • 0
    Было бы очень полезно, если бы вы включили, как выглядел фиксированный фрагмент кода.
  • 0
    Если вы должны настаивать.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню