如何向std::map中插入包含常量成员的自定义类对象?
方案合理性判断
你想到的封装std::map包装类的方案完全合理,是满足所有约束条件的最优选择之一,既可以保留map的操作效率,又能完全自定义行为限制,规避默认operator[]的隐含默认构造逻辑,同时适配不可赋值的const成员类型。
包装类参考实现
#include <string> #include <map> #include <stdexcept> struct A { const int value; A(int value) : value{value} {} }; class ConstAMap { private: std::map<std::string, A> inner_map; public: // 插入/替换接口,满足不存在则新增、存在则替换的要求 void set(const std::string& key, const A& val) { // insert_or_assign C++17及以上支持,底层直接替换节点,不需要调用元素的拷贝赋值运算符 inner_map.insert_or_assign(key, val); } // 访问接口,key不存在直接抛异常,不会默认构造对象 A& get(const std::string& key) { auto it = inner_map.find(key); if (it == inner_map.end()) { throw std::out_of_range("Key not found in ConstAMap"); } return it->second; } const A& get(const std::string& key) const { auto it = inner_map.find(key); if (it == inner_map.end()) { throw std::out_of_range("Key not found in ConstAMap"); } return it->second; } // 可按需暴露其他常用map接口 bool contains(const std::string& key) const { return inner_map.contains(key); } size_t size() const { return inner_map.size(); } void erase(const std::string& key) { inner_map.erase(key); } }; int main() { A a{3}; ConstAMap myMap; myMap.set("Hello", a); // 插入成功 A a2{5}; myMap.set("Hello", a2); // 替换成功,直接替换整个A实例,不会修改原有实例的const成员 // myMap.get("World"); // 访问不存在的key会抛出out_of_range异常 return 0; }
该实现完全满足所有要求:const成员全程不可修改、插入替换逻辑符合预期、访问不存在的key直接抛异常。
其他符合要求的实现方式
如果是小范围内部使用,不想封装完整的包装类,也可以直接用原生map配合固定操作规范实现需求:
- 插入/替换操作统一调用
std::map::insert_or_assign,禁止使用operator[] - 访问操作统一调用
std::map::at,该接口本身就会在key不存在时抛出std::out_of_range异常
示例代码如下:
int main() { A a{3}; std::map<std::string, A> myMap; myMap.insert_or_assign("Hello", a); // 插入成功 A a2{5}; myMap.insert_or_assign("Hello", a2); // 替换成功 // myMap.at("World"); // 访问不存在的key直接抛出异常 return 0; }
这种方案的缺点是没有强约束,一旦误用operator[]就会编译报错或者产生不符合预期的行为,适合团队内部有明确代码规范的场景使用。
内容的提问来源于stack exchange,提问作者Евгений Павлов
相关产品推荐
相关产品推荐

