我在自己的类A上创建了一个unordered_set
struct A {
int v;
};
struct A_eq
{
bool operator()(A* lhs, A* rhs) const {
return lhs->v == rhs->v;
}
};
struct A_hash
{
std::size_t operator()(A* obj) const {
return std::hash<int>{}(obj->v);
}
};
int main(int , char* []) {
A* a7 = new A(); A* a5 = new A(); A* a7_ = new A(); A* a5_ = new A();
a7->v = 7; a5->v = 5; a7_->v = 7; a5_->v = 5;
std::unordered_set<A*, A_hash, A_eq> s;
s.insert(a7); s.insert(a5); s.insert(a7_);
printf("dump s:");
for (auto& obj : s) {
printf("%d,", obj->v);
}
}
程序打印
dump s:5,7,
不出所料。
虽然
然后我通过
auto iter = s.find(a5_);
A* found = *iter;
printf("%d\n", found->v);
found->v = 7;
printf("dump s:");
for (auto& obj : s) {
printf("%d,", obj->v);
}
printf("\n");
s.erase(a7_);
s.erase(a7);
s.rehash(0);
printf("dump s:");
for (auto& obj : s) {
printf("%d,", obj->v);
}
printf("\n");
iter = s.find(a7_);
printf(iter==s.end()?"no 7":"has 7");
这些代码输出
5
dump s:7,7,
dump s:7,
no 7
有人能告诉我发生了什么事吗?为什么剩余的元素不被集合视为
[UNORD.REQ/5..对于同一容器中的任意两个键
您的程序通过违反此要求表现出未定义的行为。它以更改其散列的方式修改键,并使两个键在以前比较不相等的地方比较相等。
来自CPPreference.com的
容器元素不能被修改(即使是通过非常量迭代器),因为修改可能会改变元素的哈希值并损坏容器。
更确切地说,不允许修改的不仅仅是容器中直接存在的数据,还有任何影响这些元素的相等性比较的数据。虽然您没有修改容器内的位,但您确实在逻辑上修改了容器的元素,将它们从不相等更改为相等。因此,您更改了元素的哈希值并损坏了容器。垃圾接踵而至。