尝试使用容器unordered_map
并使用char*
作为密钥时感到筋疲力尽(在Windows上,我使用的是VS 2010)。我知道我必须为char*
定义我自己的比较函数,它继承自binary_function
。以下是示例程序。
#include<unordered_map>
#include <iostream>
#include <string>
using namespace std;
template <class _Tp>
struct my_equal_to : public binary_function<_Tp, _Tp, bool>
{
bool operator()(const _Tp& __x, const _Tp& __y) const
{ return strcmp( __x, __y ) == 0; }
};
typedef unordered_map<char*, unsigned int, ::std::tr1::hash<char*>, my_equal_to<char*> > my_unordered_map;
//typedef unordered_map<string, unsigned int > my_unordered_map;
my_unordered_map location_map;
int main(){
char a[10] = "ab";
location_map.insert(my_unordered_map::value_type(a, 10));
char b[10] = "abc";
location_map.insert(my_unordered_map::value_type(b, 20));
char c[10] = "abc";
location_map.insert(my_unordered_map::value_type(c, 20));
printf("map size: %d\n", location_map.size());
my_unordered_map::iterator it;
if ((it = location_map.find("abc")) != location_map.end())
{
printf("found!\n");
}
return 0;
}
我插入相同的C字符串abc
两次并查找它。第二次插入失败,unordered_map中只有一个abc
。但是,输出大小为3.似乎比较功能在此处无法正常工作。
此外,我得到了关于find
函数的另一个奇怪结果,通过多次运行程序,查找结果甚至发生了变化!有时找到字符串abc
,而其他时间找不到abc
!
有人可以帮我这个吗?非常感谢您的帮助!
+++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++
编辑:在我自己定义char*
的哈希函数后,程序正常运行。完整的程序代码如下所示。谢谢大家。
#include<unordered_map>
#include <iostream>
using namespace std;
template <class _Tp>
struct my_equal_to : public binary_function<_Tp, _Tp, bool>
{
bool operator()(const _Tp& __x, const _Tp& __y) const
{ return strcmp( __x, __y ) == 0; }
};
struct Hash_Func{
//BKDR hash algorithm
int operator()(char * str)const
{
int seed = 131;//31 131 1313 13131131313 etc//
int hash = 0;
while(*str)
{
hash = (hash * seed) + (*str);
str ++;
}
return hash & (0x7FFFFFFF);
}
};
typedef unordered_map<char*, unsigned int, Hash_Func, my_equal_to<char*> > my_unordered_map;
int main(){
my_unordered_map location_map;
char a[10] = "ab";
location_map.insert(my_unordered_map::value_type(a, 10));
char b[10] = "abc";
location_map.insert(my_unordered_map::value_type(b, 20));
char c[10] = "abc";
location_map.insert(my_unordered_map::value_type(c, 20));
printf("map size: %d\n", location_map.size());
my_unordered_map::iterator it;
if ((it = location_map.find("abc")) != location_map.end())
{
printf("found!\n");
}
return 0;
}
注意:使用char
*作为unordered_map或其他STL容器的密钥类型可能是危险的,一种安全的方式(似乎是唯一的方法)是:在main函数中,{{ 1}}或new
堆上的块(例如c字符串数组)并用c字符串填充它。将这些c字符串插入unordered_map。分配的内存块在main函数结束时释放(malloc
或delete
)。
答案 0 :(得分:1)
你的比较器很好(尽管传递nullptr是未定义的,可能应该处理)
哈希值::std::tr1::hash<char*>
正在散列指针,所以每个“abc”(通常)都在另一个桶中
您需要编写自己的哈希函数,以确保哈希(“abc”)始终给出相同的答案
现在 - 性能会很糟糕,但有一个返回0的哈希 - 你应该看到第二个“abc”匹配第一个
根据评论 - 使用std::string
简化了内存管理并提供了库支持的哈希和比较器,因此只需std::unordered_map<std::string, X>
即可。这也意味着删除unordered map
后,所有字符串都将被释放。您甚至可以安全地从堆栈中的char数组中实例化std::strings
。
如果您仍想使用char *
,那么您仍然需要自己的比较器和哈希,但是您可以使用std::shared_ptr
为您管理内存(不要使用堆栈实例 - 执行{ {1}})
然后你将有一个new char[]
,但之后没有内存泄漏的复杂情况。
如果你仍想使用std::unordered_map<shared_ptr<char *>, X>
,那么你就是在正确的轨道上,但重要的是你要使用像purify或valgrind这样的内存泄漏工具,以确保你真正控制所有的内存管理。 (这通常是任何项目的好主意)
最后,应避免使用全局变量。
答案 1 :(得分:0)
像上面那样使用字符指针作为键几乎肯定不是你想要做的。
STL容器处理存储的值,在std::unordered_map<char *, unsigned int, ...>
的情况下,你正在处理指向c字符串的指针,这些指针在随后的插入/删除检查中可能都不存在。
请注意,my_unordered_map
是一个全局变量,但您尝试插入本地字符数组a,b和c。当插入的c字符串超出范围时,您对比较函数my_equal_to()
到strcmp()
的期望是什么? (你突然有键指向随机垃圾,可以与新插入的未来值进行比较。)
重要的是,STL映射键是可复制的值,不能通过外部程序行为改变其含义。 您几乎肯定会使用std::string
或类似的关键值,即使它们的构造乍一看对您来说也很浪费。
以下内容与您打算在上面工作的内容完全一致,并且非常安全:
#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;
// STL containers use copy semantics, so don't use pointers for keys!!
typedef unordered_map<std::string, unsigned int> my_unordered_map;
my_unordered_map location_map;
int main() {
char a[10] = "ab";
location_map.insert(my_unordered_map::value_type(a, 10));
char b[10] = "abc";
location_map.insert(my_unordered_map::value_type(b, 20));
char c[10] = "abc";
location_map.insert(my_unordered_map::value_type(c, 20));
cout << "map size: " << location_map.size() << endl;
my_unordered_map::iterator it;
if ((it = location_map.find("abc")) != location_map.end()) {
cout << "found \"" << it->first << "\": " << it->second << endl;
}
return 0;
}
答案 2 :(得分:-3)
当您定义诸如“abc”之类的内容时,会为其分配一个const char *。每次在程序中编写“abc”时,都会有一个新的内存。所以:
const char* x = "abc";
const char* y = "abc";
return x==y;
总是会返回false,因为每次“abc”被写入时都会分配新的内存(抱歉,如果我听起来有点重复)。