C++ 中 map 的 insert 与 emplace:key 已存在时会覆盖吗?

先说结论

在 C++ 的 std::map 中,无论是 insert 还是 emplace,当 key 已经存在时都不会覆盖原有的值 。两者都遵循"只插入、不更新"的语义:如果容器中已经存在等价 key,插入操作直接失败(或什么都不做),原有 value 保持不变。

真正会覆盖已有值的是 operator[] 和 insert_or_assign。这是很多初学者容易混淆的地方。

insert 的行为

insert 的返回值是一个 pair<iterator, bool>,其中 bool 表示是否插入成功。key 已存在时返回 false,迭代器指向已存在的那个元素,值不会被修改。

cpp 复制代码
#include <iostream>
#include <map>
#include <string>

int main() {
    std::map<std::string, int> m;
    m.insert({"apple", 1});

    auto ret = m.insert({"apple", 100});
    std::cout << "inserted: " << ret.second << "\n";   // 0
    std::cout << "value: " << m["apple"] << "\n";      // 1,未被覆盖
    return 0;
}

可以看到,第二次插入的 100 被直接丢弃,m["apple"] 仍然是 1。

emplace 的行为

emplace 同样是"只在 key 不存在时构造并插入"。它的返回值与 insert 一致,也是 pair<iterator, bool>。key 已存在时返回 false,并且不会用新参数去覆盖旧值。

cpp 复制代码
#include <iostream>
#include <map>
#include <string>

int main() {
    std::map<std::string, int> m;
    m.emplace("apple", 1);

    auto ret = m.emplace("apple", 100);
    std::cout << "inserted: " << ret.second << "\n";   // 0
    std::cout << "value: " << m["apple"] << "\n";      // 1,未被覆盖
    return 0;
}

insert 与 emplace 的区别

两者在"是否覆盖"这一点上没有区别,真正的差异在于构造时机和参数传递方式:

  • insert 通常需要先构造出一个 value_type(即 pair<const Key, T>),再把它拷贝或移动到容器中。
  • emplace 接受构造参数,直接在容器内部原地构造元素,理论上可以少一次临时对象的构造和拷贝。

但要注意:emplace 并不保证一定比 insert 快 。如果 key 已存在,emplace 仍然可能先构造出临时对象再发现重复而丢弃,此时反而可能比 insert 多做一次构造。因此不能盲目认为 emplace 总是更优。

那什么操作会覆盖?

如果确实希望在 key 存在时更新值,应该使用下面两种方式:

cpp 复制代码
#include <iostream>
#include <map>
#include <string>

int main() {
    std::map<std::string, int> m;
    m["apple"] = 1;

    // 方式一:operator[],key 不存在会默认构造,存在则覆盖
    m["apple"] = 100;
    std::cout << m["apple"] << "\n";   // 100

    // 方式二:insert_or_assign(C++17),语义更明确
    m.insert_or_assign("apple", 200);
    std::cout << m["apple"] << "\n";   // 200
    return 0;
}

两者的区别在于:operator[] 在 key 不存在时会先默认构造一个 value,要求 T 可默认构造;而 insert_or_assign 不存在时直接插入,不要求默认构造,语义也更清晰。

对比总结

操作 key 已存在时的行为 返回值
insert 不插入,不覆盖 pair<iterator, bool>
emplace 不插入,不覆盖 pair<iterator, bool>
operator[] 覆盖(不存在则默认构造) 值的引用
insert_or_assign 覆盖(不存在则插入) pair<iterator, bool>

一句话记忆:insert 和 emplace 都是"插入",不是"赋值";要覆盖请用 operator[] 或 insert_or_assign。

相关推荐
xys_67831 分钟前
深挖C++:类和对象(中)
开发语言·c++
灿飞屋41 分钟前
Rust 编程其实很简单
开发语言·rust
MOONICK3 小时前
QT元数据
开发语言·qt
D e re k ZH3 小时前
C++ 系统学习手记:从语法细节到工程实践
开发语言·数据结构·c++·算法
灿飞屋4 小时前
Kotlin与Java虚拟机三:控制流
android·java·开发语言·后端·python·kotlin·安卓
石小石Orz4 小时前
AI 正在蚕食我们的编码能力
前端·后端·算法
xiaoye-duck4 小时前
《C++ 项目:手写大模型接入 SDK》Ollama接口设计(上):初始化、全量响应实现和测试
开发语言·网络·c++·语言模型
zaizai10075 小时前
【Effective Modern C++】学习第一章
c++