2.17、map 的 insert 和 emplace 区别?
1. 基本定义和语义区别
- • insert
- • 需要传入一个已经构造好的元素(通常是
std::pair<const Key, T>
),然后将其复制或移动到map
内部。 - • 元素先在外部构造完成,再传入
map
,map
内部通过调用拷贝/移动构造函数完成存储。
- • 需要传入一个已经构造好的元素(通常是
- • emplace
- • 直接在
map
内部原地构造元素。 - • 接受构造元素所需的参数,通过**完美转发(perfect forwarding)**将参数传递给元素的构造函数,避免临时对象的创建和不必要的拷贝/移动。
- • 直接在
2. 关键性能差异
- • 减少临时对象和拷贝/移动
- •
emplace
通过原地构造,避免了“先构造临时对象再拷贝/移动”的过程,理论上更高效,尤其适用于元素构造开销较大(如复杂对象、大内存占用类型)的场景。
- •
- • 实际性能影响视情况而定
- • 若已持有完整构造的对象(如
T obj;
),使用emplace(obj)
与insert(obj)
的性能差异可忽略,因为此时emplace
仍需调用拷贝构造函数。 - • 仅当直接传递构造参数(如
emplace(key, value)
)时,emplace
才能发挥“避免临时对象”的优势。
- • 若已持有完整构造的对象(如
3. 使用便捷性和接口差异
- • insert的参数形式
- • 通常接受
pair
对象,如map.insert(std::make_pair(key, value))
,需显式构造pair
,语法相对繁琐。
- • 通常接受
- • emplace的参数形式
- • 直接接受元素的构造参数,如
map.emplace(key, value)
,省去显式构造pair
的步骤,代码更简洁。
- • 直接接受元素的构造参数,如
- • 复杂类型的调用细节
- • 对于需要分阶段构造的复杂类型(如
value_type
的构造需要多个参数包),可能需配合std::piecewise_construct
和std::forward_as_tuple
正确转发参数,使用稍复杂。
- • 对于需要分阶段构造的复杂类型(如
4. 语义上的区别
- • 插入失败时的行为
- • 两者均遵循
map
的“唯一性约束”:若key
已存在,插入失败且不会覆盖已有元素,原元素保持不变。
- • 两者均遵循
- • 对默认构造的要求
- • 均不要求
value_type
必须有默认构造函数,这与operator[]
不同(后者会在key
不存在时默认构造value
)。
- • 均不要求
5. 结合实际面试考察重点
- • 内存管理与构造过程的理解
- • 面试官关注你是否明确:
insert
是“先外部构造+再拷贝/移动”,而emplace
是“内部原地构造”,减少了不必要的开销。
- • 面试官关注你是否明确:
- • 完美转发与变参模板的掌握
- •
emplace
依赖C++11的完美转发(std::forward
)和变长模板参数,体现对现代C++特性(如移动语义、泛型编程)的掌握。
- •
- • 接口选择的场景意识
- • 若已有构造好的对象,
insert
和emplace
差异不大;若需直接构造,emplace
更优。 - • 两者均返回
pair<iterator, bool>
,可通过bool
值判断插入是否成功(如处理冲突场景)。
- • 若已有构造好的对象,
- • 对STL演进的了解
- • 熟悉C++17新增接口(如
try_emplace
和insert_or_assign
),前者避免重复构造参数,后者支持插入或更新,体现对标准库迭代优化的跟踪。
- • 熟悉C++17新增接口(如
总结对比表
特性 | insert | emplace |
参数类型 | 需传入已构造的对象或pair |
传入元素的构造参数(内部原地构造) |
构造方式 | 先外部构造,再拷贝/移动至map |
直接在map 内部构造,避免临时对象 |
性能 | 可能产生额外拷贝/移动开销 | 减少拷贝/移动,性能更优(特定场景) |
使用便捷性 | 需显式构造pair ,语法繁琐 |
直接传递参数,语法简洁 |
是否覆盖已有元素 | 不覆盖,插入失败时保持原数据 | 同insert |
是否要求默认构造 | 不要求 | 不要求 |
本文首发于【讳疾忌医-note】公众号,未经授权,不得转载。
(加入我的知识星球,免费获取账号,解锁所有文章。)
阅读剩余
版权声明:
作者:讳疾忌医-note
链接:https://www.1217zy.vip/archives/1861
文章版权归作者所有,未经允许请勿转载。
THE END