【发布时间】:2022-01-16 04:39:04
【问题描述】:
我很抱歉我的标题模糊。
假设有一些节点的指针,我想收集具有唯一value的节点指针。
struct node_t
{
int value;
node_t(int v = -1) : value(v) {}
};
例如,如果我们有 4 个指针:
p1 points to node(1)
p2 points to node(1)
p3 points to node(2)
p4 points to node(2)
那我想在这里收集{p1, p3}。
这是我的代码写的:
#include <iostream>
#include <unordered_set>
#include <algorithm>
using namespace std;
struct node_t
{
int value;
node_t(int v = -1) : value(v) {}
};
struct myequal
{
bool operator()(const node_t *p1, const node_t *p2) const
{
return p1->value == p2->value;
}
};
int main()
{
unordered_set<node_t *, hash<node_t *>, myequal> table;
node_t n1(0), n2(0);
table.insert(&n1), table.insert(&n2);
cout << (&n1) << '\n';
cout << (&n2) << '\n';
cout << table.size() << '\n';
cout << *table.begin() << '\n';
}
我在 MacOS12 上运行代码,用clang++ -std=c++17 xxx.cpp 编译它,但它的输出不确定。
有时它会输出:
0x7ff7bad974e0
0x7ff7bad974d0
1
0x7ff7bad974e0
但有时它会输出:
0x7ff7b4bdc4e0
0x7ff7b4bdc4d0
2
0x7ff7b4bdc4d0
为什么会这样?
根据unordered_set的document,
只有当每个元素不等同于容器中已有的任何其他元素时才会插入每个元素(unordered_set 中的元素具有唯一值)。
【问题讨论】:
-
输出看起来差不多。
&n1是n1的内存地址。你只是在打印那个。输出的前两行是n1和n2这两个内存地址。第四行也是一样。*table.begin()是一个指向内存地址的指针,您正在那里打印一个指针。 -
您使用指针作为键,键存储是基于散列的。您正在散列指针本身,而不是它们指向的节点值。但是您正在使用节点值来实现键相等。您有 2 个具有相同值的节点,因此理论上表大小应为 1,但 2 个节点的哈希值不同。我认为不一致导致了您所看到的行为。
-
等效元素的哈希值必须相等。因此,如果您定义自定义相等,您还必须定义相应的自定义哈希。
-
我没有在 cplusplus.com(您的文档来源)上看到它,但如果您访问 cppreference.com 的 documentation for unordered set,则有一个指向指定要求 UnorderedAssociativeContainer 的链接。相关信息是第三段(单行,就在“since C++20”框之前)。我希望我只是忽略了 cplusplus.com 上的一些内容,因为这对于编写自己的相等运算符的人来说是一种重要信息。