Я понимаю, что код будет медленнее, но почему так много? Как мне написать код, чтобы избежать этого замедления?
std :: unordered_map использует другие контейнеры внутри, и эти контейнеры используют итераторы. При встроенной отладке _ITERATOR_DEBUG_LEVEL = 2 по умолчанию. Это включает отладку итератора . Иногда мой код не сильно подвержен влиянию, а иногда он работает очень медленно.
Я могу ускорить мой пример, установив _ITERATOR_DEBUG_LEVEL = 0 в свойствах моего проекта >> C ++ >> Препроцессор >> Определения препроцессора. Но, как подсказывает эта ссылка , я не могу сделать это в моем реальном проекте. В моем случае я получаю конфликты с MSVCMRTD.lib, который содержит std :: basic_string, созданный с _ITERATOR_DEBUG_LEVEL = 2. Я понимаю, что могу обойти проблему, статически связываясь с ЭЛТ. Но я бы предпочел не делать этого, если смогу исправить код, чтобы проблема не возникала.
Я могу внести изменения, которые улучшат ситуацию. Но я просто пробую вещи, не понимая, почему они работают. Например, как есть, первые 1000 вставок работают на полной скорости. Но если я изменю O_BYTE_SIZE на 1, первые вставки будут такими же медленными, как и все остальное. Это выглядит как небольшое изменение (не обязательно хорошее изменение).
Это , это , и это также пролило некоторый свет, но не отвечайте на мой вопрос.
Я использую Visual Studio 2010 (это устаревший код.) Я создал консольное приложение Win32 и добавил этот код.
main.cpp
#include "stdafx.h"
#include "OString.h"
#include "OTHashMap.h"
#include <cstdio>
#include <ctime>
#include <iostream>
// Hash and equal operators for map
class CRhashKey {
public:
inline unsigned long operator() (const OString* a) const { return a->hash(); }
};
class CReqKey {
public:
inline bool operator() (const OString& x, const OString& y) const { return strcmp(x.data(),y.data()) != 0; }
inline bool operator() (const OString* x, const OString& y) const { return operator()(*x,y); }
inline bool operator() (const OString& x, const OString* y) const { return operator()(x,*y); }
inline bool operator() (const OString* x, const OString* y) const { return operator()(*x,*y); }
};
int _tmain(int argc, _TCHAR* argv[])
{
const int CR_SIZE = 1020007;
CRhashKey h;
OTPtrHashMap2<OString, int, CRhashKey, CReqKey> *code_map =
new OTPtrHashMap2 <OString, int, CRhashKey, CReqKey>(h, CR_SIZE);
const clock_t begin_time = clock();
for (int i=1; i<=1000000; ++i)
{
char key[10];
sprintf(key, "%d", i);
code_map->insert(new OString(key), new int(i));
//// Check hash values
//OString key2(key);
//std::cout << i << "\t" << key2.hash() << std::endl;
// Check timing
if ((i % 100) == 0)
{
std::cout << i << "\t" << float(clock() - begin_time) / CLOCKS_PER_SEC << std::endl;
}
}
std::cout << "Press enter to exit" << std::endl;
char buf[256];
std::cin.getline(buf, 256);
return 0;
}
OTHashMap.h
#pragma once
#include <fstream>
#include <unordered_map>
template <class K, class T, class H, class EQ>
class OTPtrHashMap2
{
typedef typename std::unordered_map<K*,T*,H,EQ> OTPTRHASHMAP_INTERNAL_CONTAINER;
typedef typename OTPTRHASHMAP_INTERNAL_CONTAINER::iterator OTPTRHASHMAP_INTERNAL_ITERATOR;
public:
OTPtrHashMap2(const H& h, size_t defaultCapacity) : _hashMap(defaultCapacity, h) {}
bool insert(K* key, T* val)
{
std::pair<OTPTRHASHMAP_INTERNAL_ITERATOR,T> retVal = _hashMap.insert(std::make_pair<K*,T*>(key, val));
return retVal.second != NULL;
}
OTPTRHASHMAP_INTERNAL_CONTAINER _hashMap;
private:
};
OString.h
#pragma once
#include <string>
class OString
{
public:
OString(const std::string& s) : _string (s) { }
~OString(void) {}
static unsigned hash(const OString& s) { return unsigned (s.hash()); }
unsigned long hash() const
{
unsigned hv = static_cast<unsigned>(length());
size_t i = length() * sizeof(char) / sizeof(unsigned);
const char * p = data();
while (i--) {
unsigned tmp;
memcpy(&tmp, p, sizeof(unsigned));
hashmash(hv, tmp);
p = p + sizeof(unsigned);
}
if ((i = length() * sizeof(char) % sizeof(unsigned)) != 0) {
unsigned h = 0;
const char* c = reinterpret_cast<const char*>(p);
while (i--)
{
h = ((h << O_BYTE_SIZE*sizeof(char)) | *c++);
}
hashmash(hv, h);
}
return hv;
}
const char* data() const { return _string.c_str(); }
size_t length() const { return _string.length(); }
private:
std::string _string;
//static const unsigned O_BYTE_SIZE = 1;
static const unsigned O_BYTE_SIZE = 8;
static const unsigned O_CHASH_SHIFT = 5;
inline void hashmash(unsigned& hash, unsigned chars) const
{
hash = (chars ^
((hash << O_CHASH_SHIFT) |
(hash >> (O_BYTE_SIZE*sizeof(unsigned) - O_CHASH_SHIFT))));
}
};