C++ 自定义类作为unordered_set元素报const错误及哈希优化问题
问题解决
编译错误修复
报错的核心原因是Message类的所有get_xxx读取类成员的方法都没有加const修饰符。而以下场景中调用get_xxx的对象都是只读的const类型:
operator==的入参是const Message&- 哈希模板的入参是
const Message& unordered_set中存储的元素默认是只读的,遍历的时候拿到的是const Message&
在const对象上调用非const成员函数会触发丢弃限定符的编译错误。
只需要给所有get_xxx方法加上const修饰即可解决报错,修改后代码如下:
class Message{ public: //Constructors() struct sockaddr_in get_dst() const { return dst; } std::string get_msg() const { return message; } bool is_ack() const { return ack; } int get_seq() const { return sequence_number; } bool operator==(const Message& m2) const{ return sequence_number == m2.get_seq() && dst.sin_port == m2.get_dst().sin_port && dst.sin_addr.s_addr == m2.get_dst().sin_addr.s_addr; }; private: bool ack; int sequence_number; std::string message; struct sockaddr_in dst; };
哈希函数优化
你当前用的异或组合逻辑存在明显缺陷:异或操作满足交换律,不同字段的取值顺序不影响最终结果,会导致大量不必要的哈希冲突,比如seq=1、port=2和seq=2、port=1的哈希结果会完全相同,会大幅拉低unordered_set的增删查性能。
优化后的哈希函数可以采用通用的质数系数组合逻辑,避免交换律问题,大幅降低冲突概率,实现如下:
namespace std { template<> struct hash<Message>{ size_t operator()(const Message& m) const { std::size_t res = 17; // 初始质数种子 // 用质数系数依次合并每个字段的哈希值,无交换律 res = res * 31 + std::hash<int>{}(m.get_seq()); res = res * 31 + std::hash<unsigned short>{}(m.get_dst().sin_port); res = res * 31 + std::hash<in_addr_t>{}(m.get_dst().sin_addr.s_addr); return res; } }; }
如果需要更高的哈希分布均匀性,可以把系数31替换为更大的质数如65599,31属于常用的轻量化系数,计算速度快,绝大多数业务场景下已经够用。
内容的提问来源于stack exchange,提问作者aliruk
相关产品推荐
相关产品推荐

