为何不存在`map::insert_or_assign`的惰性版本?如何惰性使用该函数?
解决map::insert_or_assign惰性构造的问题
在高缓存命中率、值类型构造开销大的场景下,map::insert_or_assign确实会因为无条件构造值对象造成浪费——不管键是否存在,它都会先创建要赋值的对象。要实现惰性构造,核心思路是先检查键是否存在,仅在未命中时才构造值,具体有两种可行方案:
方案一:先查找再按需操作(兼容C++11及以上)
通过find()提前检查键的存在性,只有未命中时才构造并插入值对象:
#include <map> // 假设HeavyObj是构造开销极大的类型 struct HeavyObj { HeavyObj(int param) { /* 昂贵的初始化逻辑 */ } }; std::map<int, HeavyObj> cache; void process_key(int key) { auto iter = cache.find(key); if (iter != cache.end()) { // 缓存命中,直接使用现有对象,无额外构造开销 // 若需要更新缓存值,直接修改iter->second即可 iter->second = HeavyObj{key}; // 仅当确实需要更新时执行,避免无用构造 } else { // 缓存未命中,构造对象并插入(用emplace避免拷贝) auto [new_iter, inserted] = cache.emplace(key, HeavyObj{key}); // 对新插入的对象做后续处理 } }
这种方式完全避免了命中场景下的无用构造,适合无法使用C++17特性的环境。
方案二:使用C++17的try_emplace(更简洁高效)
C++17引入的try_emplace是专门为这类场景设计的:它会先检查键是否存在,仅当键不存在时才用传入的参数构造值对象;若键已存在,则直接返回现有元素的迭代器,不会触发任何构造逻辑。
#include <map> struct HeavyObj { HeavyObj(int param) { /* 昂贵的初始化逻辑 */ } }; std::map<int, HeavyObj> cache; void process_key(int key) { // try_emplace参数:键,后跟值构造函数的参数 auto [iter, inserted] = cache.try_emplace(key, key); if (inserted) { // 缓存未命中,刚完成新对象的构造与插入 } else { // 缓存命中,直接使用iter->second } }
这是最理想的解决方案,代码更简洁,且原生支持惰性构造,完全适配高命中率的缓存场景。
需要注意的是,如果你的业务逻辑要求命中时也要更新缓存值,那依然应该先通过find()定位到元素,再直接修改现有对象——不要用insert_or_assign,因为它会先构造新的HeavyObj再赋值,徒增开销。
内容的提问来源于stack exchange,提问作者Spongman
相关产品推荐
相关产品推荐

