C++中map存储unique_ptr的高效Get-or-Create实现方案求助
优化带unique_ptr子节点的树节点创建逻辑
首先,你当前用try_emplace的写法存在一个核心问题:函数实参会在try_emplace执行前提前求值,所以无论目标键是否已经存在,make_unique<Node>()都会被调用,导致不必要的对象构造和内存分配。下面是两种更优的实现方式:
方式一:封装辅助函数(推荐,简洁且复用性高)
写一个工具函数,先查找键是否存在,仅当不存在时才创建新节点:
#include <map> #include <memory> struct Node { std::map<int, std::unique_ptr<Node>> children; }; // 获取或创建指定键对应的节点 Node* get_or_create(std::map<int, std::unique_ptr<Node>>& node_map, int key) { auto it = node_map.find(key); if (it != node_map.end()) { return it->second.get(); } // 仅当键不存在时才构造新Node auto [new_it, _] = node_map.emplace(key, std::make_unique<Node>()); return new_it->second.get(); }
使用时可以链式调用,非常简洁,且完全避免不必要的构造:
std::map<int, std::unique_ptr<Node>> themap; // 创建/获取键5的节点,再创建/获取其下键6的节点 get_or_create(get_or_create(themap, 5)->children, 6);
方式二:一行式写法(无需辅助函数)
如果不想封装函数,可以直接利用find和emplace组合实现一行逻辑,同样只有键不存在时才构造对象:
std::map<int, std::unique_ptr<Node>> themap; // 处理键5的节点 auto& node5 = themap.find(5) != themap.end() ? themap[5] : themap.emplace(5, std::make_unique<Node>()).first->second; // 处理键5节点下的键6节点 auto& node6 = node5->children.find(6) != node5->children.end() ? node5->children[6] : node5->children.emplace(6, std::make_unique<Node>()).first->second;
原写法冗余开销的原因
你之前的try_emplace写法:
themap.try_emplace(5, std::make_unique<Node>()).first->second->children.try_emplace(6, std::make_unique<Node>());
问题在于,std::make_unique<Node>()作为函数实参,会在try_emplace执行前就完成调用——哪怕键5已经存在,这个临时的unique_ptr<Node>还是会被创建,随后因为try_emplace不需要插入而被销毁,造成无意义的内存分配和释放。
而上面两种方式都是先判断键是否存在,仅在必要时才构造新对象,完全消除了这种冗余开销。
内容的提问来源于stack exchange,提问作者mandarinorange
相关产品推荐
相关产品推荐

