【发布时间】:2021-09-24 14:56:41
【问题描述】:
我有一个非常简单的 POD 结构,其中包含 3 个短裤,我计划在 unordered_set 中使用它数亿次。
这是我目前正在做的事情:
struct ps3 {
short v1;
short v2;
short v3;
bool operator==(const ps3& other) const {
return v1 == other.v1
&& v2 == other.v2
&& v3 == other.v3;
}
}
// Hash function:
size_t operator()(const ps3& p) const {
return (static_cast<size_t>(*reinterpret_cast<const int*>(&p)) << 16) | p.v3;
}
哈希函数只返回 ps3 的值,因为它可以容纳在 8 个字节内。
(我看到here,对于基本类型,标准哈希函数只返回自身,所以如果它是一个值为 30 的 int,它将返回 30 的哈希)
我返回 ps3 的值,方法是获取前四个字节,移位 16,然后 OR 处理最后一个字节。
我想知道这种方法是否好用,是否有什么可以提高性能的方法(因为它被使用了数亿次,可能是数十亿次)
基准测试
我做了一些基准测试,结果如下:
- 当前方法:1076ms
- memcpy:1500ms
- 按照@rturrado 的建议,使用
hash<short>()组合每个短片:876 毫秒
【问题讨论】:
-
*reinterpret_cast<const int*>(&p)) << 16是未定义的行为。我建议使用memcpy将结构复制到unsigned long long,然后散列/返回该整数。 -
我很确定
reinterpret_cast的这种用法违反了严格的别名规则,这意味着该代码具有未定义的行为。执行此操作的正确方法是使用std::memcpy。 -
在 A Tour of C++ 一书中,他们建议对结构成员使用异或组合现有的哈希函数。在您的情况下,它将类似于
hash<short>()(v1) ^ hash<short>()(v2) ^ hash<short>()(v3)。 -
很可能不会。所有数据都应该在缓存/寄存器中,所以应该很快。
-
如果您担心性能,请不要使用
std::unorderd_set。它基本上是std::vector<std::list>和std::list是性能最差的容器之一。