try_emplace不会移动或拷贝参数,因为它仅在键不存在时才直接在容器内存中就地构造值对象,完全避免临时对象的创建与传递。
try_emplace 为什么不会移动或拷贝参数
try_emplace 的核心优势在于:它只在键不存在时才构造值对象,且直接在容器内存中就地构造,完全绕过临时对象的创建、移动或拷贝。而 insert(尤其是接受 std::pair 的重载)必须先构造一个临时 std::pair,再将其插入——哪怕键已存在,这个临时对象也白造了。
常见错误现象:insert({key, expensive_obj()}) 会无条件调用 expensive_obj(),即使 key 已存在;而 try_emplace(key, expensive_obj()) 中,expensive_obj() 只有在键缺失时才被求值。
- 使用场景:值类型构造开销大(如
std::string拼接、自定义类含资源分配)、或构造过程可能抛异常需避免冗余执行 - 注意:
try_emplace不接受std::pair,只接受可转发给Value构造函数的参数包 - 兼容性:C++17 起支持,老标准只能用
insert或emplace
insert 和 emplace 在 map 中的实际行为差异
insert 对已有键返回失败(pair 的 second 为 false),不修改原值;emplace 行为类似,但若键已存在,它仍会尝试构造 Value(只是丢弃),造成浪费;try_emplace 则彻底跳过构造——这是三者最本质的分水岭。
性能影响显著:对 std::map> 插入重复键,emplace(1, big_vector) 每次都复制 big_vector,而 try_emplace(1, big_vector) 仅第一次构造。
立即学习“C++免费学习笔记(深入)”;
-
insert(std::make_pair(k, v)):强制拷贝/移动v,且std::make_pair可能推导出错误类型(如int&退化) -
insert({k, v}):隐式构造std::pair,同样触发v的拷贝/移动 -
emplace(k, args...):转发args...构造pair,但不检查键是否存在就构造——危险
什么情况下 try_emplace 反而更慢
当 Value 是 trivial 类型(如 int、double)或廉价可移动类型,且插入几乎总是成功(即键极少重复)时,try_emplace 的额外键查找开销(先查再决定是否构造)可能略高于直接 emplace。但这种差距通常在纳秒级,实际难以测出。