如何解决std::set存储可修改成员对象的代码冗余问题?
解决方案:消除std::set中语义不符的const/mutable修饰
1. 拆分键与可变成员,改用std::map
最直接的方式是将类中的键成员和可变成员分离,用std::map替代std::set:把键作为map的key,可变部分作为map的value。这样既保留了基于键的有序性,又能自由修改value部分,完全不需要修改原类的const语义。
示例代码:
// 原Dummy类保持语义纯净,无需额外const/mutable struct Dummy { int other_member; void set_other_member(int val) { other_member = val; } }; // 使用std::map存储,键为原Dummy的key字段 std::map<int, Dummy> data_map; // 修改操作示例 auto it = data_map.find(123); if (it != data_map.end()) { it->second.set_other_member(456); // 直接修改value,无const限制 }
2. 拷贝-修改-替换原元素
如果必须保留std::set,可以采用「取出元素→修改→删除原元素→插入新元素」的流程。这种方式不需要修改原类的任何定义,严格遵循std::set的const语义,同时实现可变成员的修改。
示例代码:
struct Dummy { int key; int other_member; // 必要的比较运算符,用于std::set排序 bool operator<(const Dummy& other) const { return key < other.key; } void set_other_member(int val) { other_member = val; // 无需const修饰,语义正常 } }; std::set<Dummy> data_set; // 修改操作示例 auto it = data_set.find(Dummy{123, 0}); if (it != data_set.end()) { Dummy temp = *it; // 拷贝出可修改的副本 temp.set_other_member(456); // 修改副本的可变成员 data_set.erase(it); // 删除原元素 data_set.insert(std::move(temp)); // 插入修改后的副本(用move优化性能) }
3. 使用multi_index_container(第三方库方案)
如果你可以引入Boost库,boost::multi_index_container是更灵活的选择:它支持同时按key排序,且允许直接修改非键成员,无需破坏容器的有序性。这种方式既保留了std::set的有序查询特性,又能像普通对象一样修改非键字段。
示例简化代码:
#include <boost/multi_index_container.hpp> #include <boost/multi_index/ordered_index.hpp> #include <boost/multi_index/member.hpp> using namespace boost::multi_index; struct Dummy { int key; int other_member; void set_other_member(int val) { other_member = val; // 语义正常,无额外修饰 } }; // 定义multi_index容器,按key排序 using DummyContainer = multi_index_container< Dummy, indexed_by< ordered_unique<member<Dummy, int, &Dummy::key>> > >; DummyContainer data_container; // 修改操作示例 auto it = data_container.find(123); if (it != data_container.end()) { // 获取非const迭代器,直接修改非键成员 auto non_const_it = data_container.modify(it, [](Dummy& d) { d.set_other_member(456); }); }
内容的提问来源于stack exchange,提问作者Moravas
相关产品推荐
相关产品推荐

