【C++】set中的元素不允许修改
目录1. 有序集合如 C 的 std::set2. 无序集合如 C 的 std::unordered_set 或 Python 的 set正确的“修改”方式extract 的核心原理代码演示1. 修改 std::set 中的元素2. 修改 std::map 中的键Keyextract 的三大核心优势在 C 以及绝大多数编程语言中set集合中的元素不允许被直接修改其根本原因在于直接修改元素会破坏底层数据结构的规则和约束从而导致数据结构失效。我们可以从底层数据结构的角度来剖析这个问题1. 有序集合如 C 的std::setstd::set的底层通常是由红黑树一种自平衡二叉查找树实现的。排序规则约束红黑树在插入元素时会根据元素的值自动进行排序默认从小到大。树中的每一个节点的位置都是由它的值决定的左子树的值 根节点的值 右子树的值。修改带来的灾难如果允许直接修改树中某个节点的值比如把一个原本很小的值改成了很大的值这个节点所在的位置就不再符合二叉查找树的性质了。这会直接导致整棵红黑树“坍塌”后续的查找、插入和删除操作都会失效比如二分查找时会走错分支永远找不到目标元素。2. 无序集合如 C 的std::unordered_set或 Python 的set无序集合的底层通常是由哈希表Hash Table实现的。哈希映射约束当一个元素被放入哈希表时系统会计算它的哈希值Hash Code并根据这个哈希值将它放到特定的“桶”Bucket里。修改带来的灾难如果你直接修改了元素的值它的哈希值通常也会随之改变。但是这个元素目前仍然待在旧哈希值对应的“桶”里。当你要查找或删除修改后的新值时系统会去新哈希值对应的桶里找自然一无所获而旧的桶里则留下了一个“幽灵”数据导致内存泄漏或逻辑错误。正确的“修改”方式因为不能原地修改如果确实需要更新set中的某个元素必须遵循“先破后立”的原则分为两步删除旧元素erase插入新元素insert#includeiostream#includesetintmain(){std::setintmySet{10,20,30};// 假设我们要把 20 修改为 25autoitmySet.find(20);if(it!mySet.end()){// *it 25; // 编译报错表达式必须是可修改的左值 (因为迭代器返回的是 const 引用)mySet.erase(it);// 1. 删除旧值mySet.insert(25);// 2. 插入新值}return0;}在 C 中set的迭代器被设计为返回const引用正是为了从编译器层面强制阻止你直接修改它的值。在 C17 中确实引入了一种极其优雅且高效的机制来解决这个问题extract方法与节点句柄Node Handle。传统的eraseinsert做法最大的性能瓶颈在于内存分配与释放。erase会销毁树节点并释放内存而insert又会重新申请内存并拷贝/移动数据。在对常数级时间开销敏感的算法场景下这种反复的堆内存Heap操作代价高昂。C17 的extract完美绕过了这个瓶颈。extract的核心原理extract方法可以将一个节点直接从set或map的底层红黑树中“摘除”解除指针链接但不释放该节点占用的内存也不调用元素的析构函数。它会返回一个节点句柄node_type这个句柄拥有该节点的所有权。通过这个句柄你可以直接修改元素的键值然后再用insert把这个节点“挂”回到树中。整个过程仅仅是修改了几次树节点的指针零内存分配Zero Allocation也没有任何元素的拷贝或移动操作。代码演示1. 修改std::set中的元素在set的节点句柄中可以通过.value()直接修改被摘除元素的值。#includeiostream#includesetintmain(){std::setintmySet{10,20,30};// 1. 提取值为 20 的节点autonodemySet.extract(20);// 检查是否成功提取如果元素不存在node 会为空if(!node.empty()){// 2. 直接在内存中修改它的值node.value()25;// 3. 将修改后的节点重新插入回树中// 注意必须使用 std::move 转移所有权mySet.insert(std::move(node));}for(intx:mySet){std::coutx ;// 输出: 10 25 30}return0;}2. 修改std::map中的键Key修改map的 Key 一直是个痛点C17 之前只能复制 Value 再删除旧 Key。现在可以通过节点句柄的.key()直接修改。#includeiostream#includemap#includestringintmain(){std::mapint,std::stringmyMap{{1,Apple},{2,Banana}};// 提取 Key 为 1 的节点autonodemyMap.extract(1);if(!node.empty()){// 直接修改 Key不需要拷贝 Apple 字符串node.key()3;myMap.insert(std::move(node));}// 此时 myMap 变为: {2: Banana, 3: Apple}return0;}extract的三大核心优势极致的性能规避了new和delete带来的动态内存开销也避免了复杂对象如长字符串、大结构体的拷贝/移动成本。容器间转移除了修改键值你还可以用extract将一个节点从std::set转移到另一个std::set甚至是从std::set转移到std::multiset同样不需要任何内存分配操作。异常安全性因为没有发生内存分配重新insert节点句柄的操作是不会抛出std::bad_alloc异常的这在编写高健壮性代码时非常关键。如果你的数据结构中存储的是体积较大的对象或者在进行高频的键值更新C17 的extract是目前的最佳实践。

相关新闻

【Linux系统编程】进程的优先级

【Linux系统编程】进程的优先级

优先级概念:cpu资源分配的先后顺序 为什么会有优先级?因为资源有限,如果是单核系统,也就是只有一个CPU,它要处理多个进程的话,就必须要按照一定的顺序。 优先级的特点: ps -al $显示进程 ls…

2026/10/15 23:47:42 阅读更多 →
异构计算架构革命:从硬件革新到软件范式转移

异构计算架构革命:从硬件革新到软件范式转移

1. 演讲背景与核心观点解析 2026年CES展会上的这场主题演讲,标志着计算架构发展史上的一个重要转折点。演讲者以"旧世界,裂开了!"这个充满冲击力的标题,直指传统计算范式正在发生的根本性变革。作为从业十五年的技术观察…

2026/10/13 5:02:11 阅读更多 →
XDS510仿真器接口设计:时序计算与EMU引脚配置实战指南

XDS510仿真器接口设计:时序计算与EMU引脚配置实战指南

1. 项目概述:XDS510仿真器设计的核心挑战在嵌入式系统,尤其是基于TI DSP的开发过程中,仿真器是连接开发环境与目标硬件的生命线。它不仅仅是下载代码的工具,更是我们窥探芯片内部运行状态、实时追踪变量、设置断点、进行性能剖析的…

2026/10/10 17:17:25 阅读更多 →

最新新闻

CCNA必学:交换机MAC地址静态绑定与端口安全实战指南

CCNA必学:交换机MAC地址静态绑定与端口安全实战指南

1. 从一个真实故障说起:为什么MAC地址绑定不是选修课刚入行那会儿,我在一个中小型企业的网络改造项目里踩过一个经典的坑。当时办公区一台接入层交换机下面挂了二十多台设备,某天开始间歇性断网,用户反馈时好时坏,重启…

2026/10/15 23:47:01 阅读更多 →
vue3+taro+Nutui 开发小程序(一):用 TaoToken 统一 Key 打通多端调试链路

vue3+taro+Nutui 开发小程序(一):用 TaoToken 统一 Key 打通多端调试链路

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

2026/10/15 23:47:01 阅读更多 →
FPGA实现8x8二维DCT:从算法选型到硬件架构全复盘

FPGA实现8x8二维DCT:从算法选型到硬件架构全复盘

最近刚把一个二维离散余弦变换(DCT)的FPGA实现完整跑通,8x8块,行变换-转置-列变换两级流水,行为仿真和上板实测结果一致,误差控制在允许范围内。DCT这东西,教科书上几行公式就能写完&#xff0c…

2026/10/15 23:47:01 阅读更多 →
Cursor 如何添加免费的大模型:把 Base URL 改到 TaoToken 的完整配置与验证

Cursor 如何添加免费的大模型:把 Base URL 改到 TaoToken 的完整配置与验证

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

2026/10/15 23:47:01 阅读更多 →
Linux eventfd:内核级事件计数器原理与C++ RAII封装

Linux eventfd:内核级事件计数器原理与C++ RAII封装

1. 为什么 eventfd 不是“另一个 pipe”,而是内核级事件计数器的优雅接口在 Linux 系统编程中,当开发者第一次听说 eventfd 时,常会下意识把它和 pipe、socketpair 或 signalfd 归为一类——“不就是个用于线程/进程间通知的文件描述符嘛”。…

2026/10/15 23:47:01 阅读更多 →
子网划分原理与实战:从课后题1理解网络分段本质

子网划分原理与实战:从课后题1理解网络分段本质

1. 这道题不是“做作业”,而是打开网络世界的第一把钥匙“计算机网络原理 课后题1”——看到这行字,很多人第一反应是翻教材、查答案、抄个IP地址配个子网掩码就完事。但我在某高校连续带了七年《计算机网络原理》实验课,带过三百多名学生&am…

2026/10/15 23:46:00 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/15 9:49:14 阅读更多 →