如何修改unordered_set中自定义类对象的非键字段而不改动哈希键
解决方案
方案1:用mutable修饰非键字段(推荐)
这是最贴合你场景的原生C++特性,mutable专门用于标记const对象中允许修改的、不影响对象等价性的成员,完全符合你的需求:仅修改非键的val字段,不修改参与哈希、比较的key字段。
你只需要修改myClass的成员声明即可:
class myClass { private: std::string key; mutable std::string val; // 添加mutable修饰 public: // getter建议添加const修饰,符合const正确性要求 std::string getKey() const; std::string getVal() const; void setKey(std::string key); // setVal可声明为const成员,因为修改的是mutable字段 void setVal(std::string val) const; myClass(std::string key); myClass(std::string key, std::string val); };
修改后你原有的调用代码无需改动即可正常编译运行,没有未定义行为,也没有额外的性能开销。
方案2:外层封装包装结构体(无需修改原有myClass定义)
如果你没有权限修改myClass的源码,可在存入unordered_set时套一层包装结构体,将哈希、比较的逻辑绑定到外层的key提取操作,内层的myClass可直接修改:
struct myClassWrapper { myClass inner; // 完美转发构造函数,兼容原有myClass的构造逻辑 template<typename... Args> myClassWrapper(Args&&... args) : inner(std::forward<Args>(args)) {} // 对外提供key访问,供哈希器、比较器调用 const std::string& getKey() const { return inner.getKey(); } }; // 调整后的哈希器、比较器,针对wrapper提取key计算 struct myClassWrapperHasher { size_t operator()(const myClassWrapper& wrapper) const { return std::hash<std::string>()(wrapper.getKey()); } }; struct myClassWrapperComparator { bool operator()(const myClassWrapper& a, const myClassWrapper& b) const { return a.getKey() == b.getKey(); } };
之后容器声明替换为:
std::unordered_set<myClassWrapper, myClassWrapperHasher, myClassWrapperComparator> myClassUset;
查找后修改的逻辑调整为:
auto it = myClassUset.find(myClassWrapper{some_key}); if (it != myClassUset.end()) { it->inner.setVal(some_val); }
这种方案同样没有未定义行为,也不需要做元素的取出、删除重插入操作。
重要提示:以上两种方案的前提是你修改的字段绝对不会参与哈希值计算和相等性判断,如果你误改了
key字段,会破坏unordered_set的内部存储结构,触发未定义行为,这个是所有无序关联式容器的通用约束。
内容的提问来源于stack exchange,提问作者quaz0
相关产品推荐
相关产品推荐

