何时应该为`std :: unordered提供我们自己的Hash函数
当我编译下面的代码时,我看到了与哈希相关的错误。
int F_no_meaningA(unordered_set<vector<int>>& setVec, vector<int>& vec)
{
setVec.insert(vec);
return 1;
}
int main()
{
vector<int> W{2, 3, 7};
unordered_set<vector<int>> setVec;
}
$ g++ --version
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
$ g++ $1.cpp -o $1 -g -Wall -Weffc++ -pedantic -std=c++0x
/tmp/ccCQFQ4N.o:在函数中`std :: __ detail :: _ Hash_code_base
,std :: vector>,std :: _ Identity >>,std :: equal_to >>,std :: hash >>,std :: __ detail :: _ Mod_range_hashing,std :: __ detail :: _ Default_ranged_hash,false> :: _ M_hash_code( std :: vector> const&)const':/usr/include/c++/4.6/bits/hashtable_policy.h:753:对std::hash<std::vector<int, std::allocator<int> > ::operator()(std::vector<int, std::allocator<int> >) const' /tmp/ccCQFQ4N.o: In function
未定义引用std::hash<std::vector<int, std::allocator<int> > ::operator()(std::vector<int, std::allocator<int> >) const' /tmp/ccCQFQ4N.o: In function
std :: __ detail :: _ Hash_code_base,std :: vector>,std :: _Identity>>,std :: equal_to>>,std :: hash>>,std :: __ detail :: _ Mod_range_hashing,std :: __ detail :: _ Default_ranged_hash,false> :: _ M_bucket_index(std :: __ detail :: _ Hash_node>,false > const *,unsigned int)const':/usr/include/c++/4.6/bits/hashtable_policy.h:763:对`std :: hash> :: operator()(std :: vector>)的未定义引用const' collect2:ld返回1退出状态
然后,我介绍下面的自己的哈希,问题就解决了。
问题1 >什么时候应该为std::unordered_set
提供我们自己的Hash? 什么时候应该为std::unordered_set
提供我们自己的等价函数?
struct HashVector : unary_function<vector<int>, vector<int>::size_type> {
vector<int>::size_type operator()(const vector<int>& vec) const {
vector<int>::size_type sum = 0;
for(int i : vec) {
sum = sum*37 + hash<int>()(i);
}
return sum;
}
};
int F_no_meaningB(unordered_set<vector<int>, HashVector>& setVec, vector<int>& vec)
{
setVec.insert(vec);
return 1;
}
int main()
{
vector<int> W{2, 3, 7};
unordered_set<vector<int>, HashVector> setVec;
}
警告:基类'struct std :: unary_function,unsigned int>'有一个非虚拟析构函数[-Weffc ++]
问题2 >为什么g ++用上面的警告抱怨struct HashVector?
谢谢
什么时候应该为std::unordered_set
提供我们自己的Hash?
当你使用一个没有标准库提供的散列的类型时。 例如,它不提供标准容器的散列函数,包括vector<int>
。
为什么g ++用上面的警告抱怨struct HashVector?
因为您已经使用过-Weffc++
来请求一个(稍微过分热心)的警告,以告诉您何时从没有虚拟析构函数的类继承。 对于大多数继承的用法(即多态),你不想这样做。 但是,在这种情况下,只是使用继承(或者可能会说滥用)来向类中注入一些定义,所以警告并不表示问题。
像std::unary_function
这样的类已经被弃用了,所以最好的解决方案就是不要继承它。
什么时候应该为std :: unordered_set提供我们自己的Hash?
该标准只需要有限数量的专业化,主要用于原始类型。 这是因为这些基本类型具有实现可以提供的一些合理的默认“一刀切”散列函数。 更复杂的类型(例如自定义类型或容器)没有明显的甚至合理的默认散列,因此您需要提供自己的默认散列。 如果您的值类型不受支持,则必须为其提供散列函数实现。
此外,提供自己的哈希函数的另一个原因是,当您有关于unordered_set
中值分布的其他专家知识时。 哈希表的性能对散列函数与存储在表中的值的分布的恰当程度非常敏感。 这是一个更完整的解释。 标准的默认设置只是一种万能的解决方案,这意味着它很容易和方便,但几乎总是次优。
为什么g ++用上面的警告抱怨struct HashVector?
这主要是应用与经典的面向对象编程相关的警告(使用基类作为派生类的动态多态接口)。 在这种情况下,不定义析构函数是虚拟的(这允许从基类实例正确销毁派生类)(例如, delete base_ptr;
)。正如Mike所说,这是一个非常严重的错误因为-Weffc++
被启用(它主要应用新手级别的经典OOP风格的警告消息)。然而,在你的代码中,继承被用在泛型编程的上下文中,继承以一种非常不同的方式使用(主要是imbue一个具有一些地面工程属性和特性的类)在这种情况下,基类没有虚拟析构函数并不是一个问题,因为它不是用于动态多态设置,而是用于静态多态设置。
还要注意std::unary_function
(及其亲属)在最新标准(C ++ 11)中已被弃用。 这是因为最新标准提供了对类型自省的改进(使用<type_traits>
, decltype
和类型推断)。
上一篇: When should we provide our own Hash function for `std::unordered