首页/新闻资讯/正文详情

C++中的map使用方法详解

发布时间:2026/11/7 7:13:00 来源:云帆数科 栏目:资讯中心
C++中的map使用方法详解
前言std::map是 C 标准库的有序关联容器键唯一、按比较器规定的顺序排列、底层通常是一棵平衡二叉搜索树。它最常被误解的地方有三个以为遍历顺序等于插入顺序以为operator[]只是读不知道它在键不存在时会插入一个默认值以为it-first可以像普通成员一样修改结果编译报错。这三个误解都源自同一个设计map的元素是std::pairconst Key, T键是常量因为一旦允许改键红黑树的有序结构就被破坏了。理解这一点operator[]为什么要默认构造、find为什么返回迭代器而不是值、删除为什么只能用erase就都顺了。本文按插入与访问 → 查找与删除 → 比较器与遍历的顺序讲重点放在接口的返回值、失效规则和几个容易写错的边界。示例以 C17 为基准contains这类 C20 才有的接口会单独标注。一、结构特征与选型std::mapKey, T, Compare, Allocator的四个模板参数里日常只用前两个。它的核心承诺是键唯一同一个键最多一个元素需要重复键用std::multimap。有序按Compare严格弱序排列遍历时从小到大。节点式存储每个元素单独分配节点插入删除不会让其他元素的引用、指针失效。对数复杂度查找、插入、删除都是 O(log n)。容器顺序查找内存适用std::map按键排序O(log n)每节点额外指针与颜色位需要有序遍历、范围查询std::unordered_map无序平均 O(1)最坏 O(n)桶数组 节点只做精确查找std::multimap按键排序O(log n)同 map允许重复键如果只需要按键快速查unordered_map通常更合适需要lower_bound、按序遍历、稳定的引用才选map。注意无序容器的遍历顺序标准不保证不能依赖。二、插入与访问map的插入接口有五个返回值与语义各不相同混用会产生不同的默认构造行为。// 适用于 C17#include map#include stringstd::mapstd::string, int m;m[apple] 1; // 不存在则插入 {apple, 0} 再赋值m.insert({banana, 2}); // 键已存在则不插入m.emplace(cherry, 3); // 原地构造m.try_emplace(date, 4); // C17键存在时不构造 valuem.insert_or_assign(apple, 10); // C17存在则赋值几个接口的差异值得记牢operator[]要求T可默认构造。键不存在时先插入T{}再返回引用因此用它查会悄悄改变容器大小。insert与emplace返回std::pairiterator, boolbool表示是否真正插入。键已存在时迭代器指向已有元素值不变。try_emplace与emplace的区别在于键已存在时emplace仍会构造实参再丢弃try_emplace不会构造 mapped 值。对昂贵的T这个差别有意义。insert_or_assign是有则改、无则插不要求T默认构造。at(key)在键不存在时抛std::out_of_range是只读访问的推荐写法const map上不能用operator[]。// 适用于 C17int ref m[apple]; // 键不存在时会插入ref 1;int v m.at(banana); // 不存在则抛异常不会插入auto it m.find(cherry); // 不存在返回 m.end()if (it ! m.end()) {it-second 30; // 值可改// it-first x; // 错误键是 const}map的迭代器解引用得到std::pairconst Key, T所以it-first的类型是const Keyit-second可写。这不是实现细节而是类型系统强制的约束。三、查找、范围与删除精确查找用find或count需要第一个不小于某键的元素用lower_bound需要范围用equal_range。这些接口都依赖比较器因此要求键之间可比较。// 适用于 C17#include iostreamauto it m.lower_bound(b); // 第一个键 b 的元素auto up m.upper_bound(b); // 第一个键 b 的元素auto range m.equal_range(b); // {lower_bound, upper_bound}for (auto p range.first; p ! range.second; p) {std::cout p-first p-second \n;}std::size_t n m.erase(apple); // 返回删除的元素个数0 或 1删除有三种重载返回类型不同重载返回说明erase(key)size_type删除的个数map为 0 或 1erase(iterator)指向被删元素之后的迭代器C11 起循环中安全使用erase(first, last)指向last的迭代器区间删除map是节点式容器插入不会让其他元素的迭代器、引用、指针失效删除只让指向被删元素的迭代器失效。这一点与std::vector的扩容全失效形成鲜明对比也是map常被用来存放地址稳定的对象的原因。循环删除要写成先取后继再删// 适用于 C17for (auto it m.begin(); it ! m.end(); ) {if (it-second 0) {it m.erase(it); // C11 起 erase 返回下一个位置} else {it;}}不要在erase(it)之后再去it那个迭代器已经失效自增是未定义行为。四、自定义比较器与遍历顺序默认比较器是std::lessKey对内置类型就是。自定义比较器必须满足严格弱序strict weak ordering不可自反、传递、且不可比较关系可传递。写成会破坏不可自反性std::map的行为随之变成未定义。// 适用于 C17#include algorithm#include cctype#include map#include stringstruct CaseInsensitiveLess {bool operator()(const std::string a, const std::string b) const {return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(),[](unsigned char x, unsigned char y) {return std::tolower(x) std::tolower(y);});}};std::mapstd::string, int, CaseInsensitiveLess ci;比较器是容器类型的一部分两个使用不同比较器的map是不同类型不能互相赋值。比较器对象会被容器复制保存如果它持有状态要保证复制后语义一致。遍历顺序由比较器决定与插入顺序无关// 适用于 C17for (const auto kv : m) {// kv.first 递增排列}需要按值排序时不能直接对map用std::sort迭代器是双向的且元素键不可改应把元素复制到std::vectorstd::pairKey, T再排序或者维护一个反向索引。常见坑点1. 用operator[]做只读查找// ❌ 键不存在时插入默认值容器变大if (m[key] 0) { /* ... */ }// ✅ 查找用 find 或 atauto it m.find(key);if (it ! m.end() it-second 0) { /* ... */ }2. 在const map上用operator[]// ❌ 编译错误const 版本没有 operator[]int v cm[key];// ✅ 用 at可能抛异常或 findint v cm.at(key);3. 试图修改键// ❌ 键类型是 const Key编译错误it-first new;// ✅ 删旧插新m.erase(it);m.emplace(new, value);4. 比较器写成// ❌ 违反严格弱序行为未定义return a b;// ✅ 只用小于return a b;5. 循环里erase后继续自增// ❌ 迭代器已失效自增是未定义行为for (auto it m.begin(); it ! m.end(); it) {if (bad(*it)) m.erase(it);}// ✅ 用 erase 的返回值推进for (auto it m.begin(); it ! m.end(); ) {it bad(*it) ? m.erase(it) : std::next(it);}6. 以为遍历顺序是插入顺序// ❌ 依赖插入顺序做输出结果按键排序for (const auto kv : m) print(kv);// ✅ 需要插入顺序就另存一个 vector 记录键std::vectorstd::string order;7. 用emplace构造昂贵的值却忽略键已存在// ❌ 即使键存在实参也会被构造后丢弃m.emplace(key, BigObject(args...));// ✅ C17 用 try_emplace键存在时不构造m.try_emplace(key, args...);8. 在map上保存元素的地址后又erase了它// ❌ 指向被删元素的指针/引用悬垂T* p m[key];m.erase(key);// ✅ 删除后不再使用该地址其他元素的地址不受影响总结操作推荐接口关键点插入不覆盖insert/emplace/try_emplace返回pairiterator,bool插入或覆盖insert_or_assignC17不要求默认构造读取不存在则抛at可用于const map读取不存在则插operator[]会改变容器大小查找find/count返回迭代器或个数范围lower_bound/upper_bound依赖比较器删除erase按迭代器删除返回下一个位置std::map的接口不算多真正要记住的是三条约束键是常量、遍历按比较器排序、operator[]会插入。把查找和访问分开写find判空再取值或at直接抛异常再保证比较器是严格弱序日常使用中绝大多数坑都可以避开。

相关推荐

JSP购物车实战:用Session实现用户私有数据持久化
JSP购物车实战:用Session实现用户私有数据持久化

简介:这是一份面向Java Web初学者的轻量级购物车系统实战案例,聚焦JSPServletTomcatSession核心技术栈,帮助开发者快速掌握电商基础功能的实现逻辑与前后端协同机制。资源共62个文件,包含13个可读性良好的Java源码(覆盖… · 2026/11/7 7:18:34

趋势跟踪策略什么时候该平仓?拆一个双反转策略:反转定方向、涨跌幅拨开关,30 天 52 次离场没有一次是止损
趋势跟踪策略什么时候该平仓?拆一个双反转策略:反转定方向、涨跌幅拨开关,30 天 52 次离场没有一次是止损

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/7 13:57:26

指纹浏览器内核源码定制技术解析:OEM 贴牌能改什么、不能改什么
指纹浏览器内核源码定制技术解析:OEM 贴牌能改什么、不能改什么

指纹浏览器的内核源码定制指在浏览器内核(Chromium 系)层面进行二次开发,以实现产品级的指纹策略、协议栈与性能改造,区别于仅在 UI 或配置层做封装的"换皮式贴牌"。结论:评估 OEM 厂商时应把「内核可定制范… · 2026/11/7 15:36:01

电工证异地可以补证千万别踩坑 3个关键点教你避坑
电工证异地可以补证千万别踩坑 3个关键点教你避坑

电工证异地可以补证千万别踩坑 3个关键点教你避坑 怕考不过白交培训费,这是很多人第一次报考电工证时的普遍焦虑。尤其是像焦作这样的三线城市,本地培训机构少、信息不对称,一不小心就掉进坑里。今天就从一个焦作初次报考者的角度,详细聊聊【电工证异地… · 2026/11/8 3:05:09

施耐德电工证有用吗?含金量真的高吗?
施耐德电工证有用吗?含金量真的高吗?

施耐德电工证有用吗?含金量真的高吗? 学历不高怕报不上名?别急,施耐德电工证含金量高不高,看完这篇你就明白了。尤其是像你这样想转行、跨省办证、补办证书的小伙伴,更要搞清楚这本证到底值不值得考。 施耐德电工证到底有什么用?… · 2026/11/8 3:05:09

安监局电工作业证考证怎么报名不被坑 电子证书怎么查
安监局电工作业证考证怎么报名不被坑 电子证书怎么查

安监局电工作业证考证怎么报名不被坑 电子证书怎么查 你是不是也遇到过这种情况,想考个电工证,但不知道去哪报名,怕被中介坑?现在市面上培训机构五花八门,价格也参差不齐,让人无从下手。别急,这篇文章就从 鹤壁应届工程类毕业生… · 2026/11/8 3:05:09

强直可以考电工证吗 电工证过期别慌 考前押题帮你拿分
强直可以考电工证吗 电工证过期别慌 考前押题帮你拿分

强直可以考电工证吗 电工证过期别慌 考前押题帮你拿分 证书过期了不知道怎么复审延期?这种情况在特种作业操作证领域非常常见,尤其是一些老电工、临时工或者刚入行的新人,往往忽略了证书的有效期,等到需要上岗时才发现问题。别担心,今天就来聊聊【强直… · 2026/11/8 3:05:09

初级电工证要多久时间 上岗必备全解析
初级电工证要多久时间 上岗必备全解析

初级电工证要多久时间 上岗必备全解析 实操考试心里没底怕挂科,这是很多想考初级电工证的朋友心里的真实想法。尤其是在转岗或跨省办理过程中,信息不对称、流程复杂,让很多人在报名前就打起了退堂鼓。但别担心,本文从 上岗必备… · 2026/11/8 3:05:09

武汉哪里能审电工证千万别踩坑
武汉哪里能审电工证千万别踩坑

武汉哪里能审电工证千万别踩坑 怕考不过白交培训费?很多学员在报考电工证时都遇到过这样的问题,尤其是第一次报考的小伙伴,生怕花了钱又白忙一场。今天就带你聊聊武汉哪里能审电工证、怎么避坑,让你少走弯路。 电工证的用途到底有多重要?… · 2026/11/8 3:04:09

电工证丢失还能补吗?千万别踩坑,丢了证等于失业
电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/8 0:00:20

电力电缆作业证直播报名入口与办理流程良心建议
电力电缆作业证直播报名入口与办理流程良心建议

电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/8 0:00:20

英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑

英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/8 0:00:20

电工证丢失还能补吗?千万别踩坑,丢了证等于失业
电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/8 0:00:20

电力电缆作业证直播报名入口与办理流程良心建议
电力电缆作业证直播报名入口与办理流程良心建议

电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/8 0:00:20

英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑

英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/8 0:00:20

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/7 11:25:08

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/7 12:02:18

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/8 1:18:25

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码