【发布时间】:2015-10-24 16:21:18
【问题描述】:
Pred:unordered_set 对象使用此表达式来确定两个元素键是否等价。 unordered_set 容器中的任何两个元素都不能具有使用此谓词产生 true 的键。
也来自 23.5.6.1/1:
unordered_set 是一个无序关联容器,它支持唯一键(unordered_set 最多包含每个键值一个),其中元素的键是元素本身。 unordered_set 类支持前向迭代器。
但如果我定义自己的散列器和使用类类型的不同功能的等效操作,我可以绕过这个。
#include <iostream>
#include <unordered_set> //for unordered_set and unordered_multiset
using namespace std;
struct A{
A() = default;
A(int a, int b): x(a), y(b) {}
int x = 0, y = 0;
};
size_t hasher(const A &sd){
return hash<int>()(sd.x);
}
bool eqOp(const A &lhs, const A &rhs){
return lhs.y == rhs.y;
}
int main(){
unordered_set<A, decltype(hasher)*, decltype(eqOp)*> unorderedA(10, hasher, eqOp);
unorderedA.emplace(2,3);
unorderedA.emplace(3,3);
for(const auto& c : unorderedA)
cout << c.x << " " << c.y << endl;
}
输出;
3 3
2 3
我了解发生了什么:哈希器将每个键放在不同的桶中,因为它们的 x 值。但是,由于它们的 y 值,我的 eqOp 函数应该认为这两个键相等,但是由于它们被放置在不同的存储桶中,因此从未检查它们是否相等。一个无序的容器可以包含两个等效的键,只要它们进入不同的桶,这是否是正常的功能。还是编码器有责任确保编写散列器和谓词以将等效键放在同一个存储桶中?或者我的 eqOp 函数是否违反了编译器未检测到的规则?
在 set 和 map 中很明显:提供给它们的谓词定义了严格的弱排序,因此两个被视为等效的键只有一个元素与它们关联。在无序映射中,我不太清楚:两个等效键可以具有与之关联的不同元素,只要这些键位于不同的存储桶中。但是上面的那些消息来源感觉就像他们告诉我的那样。
【问题讨论】:
-
“或者是编码人员有责任确保哈希器和谓词被写入以将等效键放在同一个桶中?”我敢打赌。否则,如果您在两个等效元素之间发生冲突(对于您的 operator==),您将不会插入两个元素。
标签: c++ hash unordered-set