JSON for Modern C++(nlohmann/json)值修改完全指南:push_back、emplace、update 与 erase 实战

发布时间:2026/11/4 12:43:30

JSON for Modern C++(nlohmann/json)值修改完全指南:push_back、emplace、update 与 erase 实战 JSON for Modern Cnlohmann/json值修改完全指南push_back、emplace、update 与 erase 实战【免费下载链接】jsonJSON for Modern C项目地址: https://gitcode.com/GitHub_Trending/js/json创建 JSON 值只是第一步实际开发中绝大多数工作是“修改”向数组追加元素、向对象插入或替换成员、将两个对象合并、按需删除或清空数据。本文以 nlohmann/jsonJSON for Modern C官方文档 modifying_values 为主线系统讲解对已存在 JSON 值进行增、改、并、删的全部核心 APIpush_back/emplace_back、operator[]/emplace、update、erase/clear。读完本文你将掌握每个修改接口的调用方式、null值的隐式类型转换规则、复杂度与异常语义以及递归合并、按“不存在才插入”实现等真实工程场景的推荐写法。修改操作的全景增、改、并、删nlohmann/json 把 JSON 值建模为nlohmann::basic_json通常简写为json对已存在值的修改可分为四类操作面向类型主要 API语义追加/新增数组push_back、emplace_back、operator末尾追加元素插入/替换对象operator[]、emplace、push_back插入或整体覆盖键合并对象update、JSON Merge Patch把另一对象的成员拷入并覆盖删除/清空全部erase、clear移除成员/元素或清空值对于只读访问at、find、value等请参见官方文档 element access本文聚焦可变操作。所有修改接口都以json方式就地作用于调用对象无需重新赋值除少数显式重载外。贯穿全文的一个重要设计null的隐式转换。未初始化的json j;其类型是null。库中多数“插入类”函数在检测到调用目标是null时会先把它就地转换成对应容器数组或空对象再执行插入因此可以用一条语句从零开始构建结构见下文各节。向数组追加元素push_back 与 emplace_back基本用法与 operator向数组追加元素最直接的方式是push_back。从官方示例可以看到null到数组的自动转换json j; // null j.push_back(1); // [1] j.push_back(2); // [1,2] j.emplace_back(3); // [1,2,3] // operator is a shorthand for push_back j 4; // [1,2,3,4]j初始为null第一次push_back(1)时被隐式转换为[ ]再追加元素所以不必先手动j json::array()。operator等价于push_back是追加标量/值的最紧凑写法。对应完整可运行示例可在 examples/push_back.cpp 中找到其渲染输出见 examples/push_back.output。push_back 的三组重载从 API 文档 push_back.md 看push_back实际有 3 组重载// (1) 追加元素到数组末尾 void push_back(basic_json val); void push_back(const basic_json val); // (2) 把对象元素插入 JSON 对象object_t::value_type 即 key-value 对 void push_back(const typename object_t::value_type val); // (3) 用初始化列表调用 void push_back(initializer_list_t init);值得说明的是重载 (3)当当前值是对象、初始化列表恰好含两个元素、且第一个元素是字符串时该列表会被解释为一个对象的键值对插入否则被转换为普通 JSON 值按数组语义追加。这种二义性处理源自历史 issue见库注释目的是让{{key, value}}之类写法能正确落到对象语义上。对应示例见 examples/push_back__object_t__value.cpp 与 examples/push_back__initializer_list.cpp。emplace_back就地构造emplace_back不要求先构造好basic_json而是直接把可变参数args转发给basic_json的某个构造函数在数组末尾就地构造并返回新元素的引用templateclass... Args reference emplace_back(Args ... args);这在需要追加“由多个来源组装的值”时能省去一次临时对象拷贝/移动。例如追加一个由初始化列表构造的嵌套对象j.emplace_back(json{{x, 1}, {y, 2}})。若调用目标为null同样先转为空数组。自 3.7.0 起该函数返回被插入元素的引用更早版本无返回值见 emplace_back.md。复杂度与异常数组语义接口复杂度非法类型抛出push_back(1)/(3) 追加到数组平摊常数type_error.308cannot use push_back() with typepush_back(2) 插入对象O(log(size()))type_error.308emplace_back平摊常数type_error.311cannot use emplace_back() with type这些异常码与消息在实现中被集中抛出例如 include/nlohmann/json.hpp 中JSON_THROW(type_error::create(308, ...))。也就是说对number、string等非数组也非null的值调用追加接口会直接抛出type_error而不是“自动转型”。迭代器失效规则值得在循环中留意向数组追加可能引发重新分配reallocation此时全部迭代器含end()与元素引用均失效若未发生重分配仅end()失效。对于使用ordered_json的场景向对象追加成员也可能触发重新分配并使所有迭代器、引用失效见 push_back.md 与 emplace_back.md。若需在遍历的同时插入建议先收集再批量修改或使用索引访问。向对象添加与替换成员operator[] 与 emplaceoperator[]插入即替换对象修改最常用的方式是operator[]键不存在则插入存在则整体替换对应值这是官方的推荐入口json j; j[name] Mary; // {name:Mary} j[name] John; // {name:John} (replaced)operator[]同时服务于“读取 写入”对不存在的键做写访问会创建一个值为null的新成员其完整语义见 API 文档 operator[]。这种“插入或覆盖”语义适合大多数场景但注意它总是整体替换如果旧值是一个对象而新值是标量旧对象内容会被直接丢弃不会逐层合并。emplace仅当键缺失时插入add-if-absent如果业务需求是“只在键不存在时写入已存在则跳过”应使用emplacetemplateclass... Args std::pairiterator, bool emplace(Args ... args);它把args就地构造成一个对象成员仅当容器中尚不存在该键才插入返回值中bool表示是否真的发生了插入iterator指向新插入元素或已存在的同名元素json j; auto [it, inserted] j.emplace(a, 1); // inserted true auto [it2, inserted2] j.emplace(a, 2); // inserted2 false, a 仍为 1这是实现“合并时不覆盖用户显式设置”之类语义的便捷工具。若调用目标为null会先隐式转为空对象。相关特性复杂度 O(log(size()))异常时提供强异常保证strong guarantee抛出异常则任何 JSON 值都不变对非对象或null以外的类型调用抛出type_error.311cannot use emplace() with number。从源码结构看对象成员实际存储于object_t默认为std::mapstd::string, json中因此emplace/按键插入的时间复杂度为 O(log n)与std::map的插入语义一致。合并对象update 的浅合并与递归深合并合并两个对象是配置文件合并、默认参数合并中最常见的操作。nlohmann/json 为此提供update其语义受 Python 的dict.update启发——把另一个对象的所有成员拷入重复键默认被覆盖。两种签名// (1) 从另一个 JSON 对象合并 void update(const_reference j, bool merge_objects false); // (2) 从同一 JSON 对象上的迭代器区间 [first, last) 合并 void update(const_iterator first, const_iterator last, bool merge_objects false);实现上重载 (1) 只是把参数转发给重载 (2)update(j.begin(), j.end(), merge_objects)见 include/nlohmann/json.hpp。merge_objectsfalse 与 true 的差别merge_objects false默认源对象中已存在的键被整体覆盖浅合并。merge_objects true当源对象中某键的值是对象且目标对象中该键的已有值也是对象时对该键递归执行合并其余情况值非对象、键不存在、已有值非对象仍按覆盖处理。官方示例 examples/update.cpp 同时演示了两种模式。它先构造两个对象json o1 R( {color: red, price: 17.99, names: {de: Flugzeug}} )_json; json o2 R( {color: blue, speed: 100, names: {en: plane}} )_json; json o3 o1; // add all keys from o2 to o1 (updating color, replacing names) o1.update(o2); // add all keys from o2 to o1 (updating color, merging names) o3.update(o2, true);输出examples/update.output清晰展现了差异{ color: blue, names: { en: plane }, price: 17.99, speed: 100 } { color: blue, names: { de: Flugzeug, en: plane }, price: 17.99, speed: 100 }第一个输出中names被o2的值整体替换de丢失第二个输出中names被递归合并de与en共存。实现机理何时才递归update的合并逻辑可以在 include/nlohmann/json.hpp 中看到for (auto it first; it ! last; it) { if (merge_objects it.value().is_object()) { auto it2 m_data.m_value.object-find(it.key()); // Only recurse when the existing value is itself an object. // Otherwise overwrite, matching the documented all other values // are overwritten as usual behavior (see #5402). if (it2 ! m_data.m_value.object-end() it2-second.is_object()) { it2-second.update(it.value(), true); // ... JSON_DIAGNOSTICS 下维护 m_parent continue; } } m_data.m_value.object-operator[](it.key()) it.value(); }两个细节值得注意递归发生的前提是两端同键的值都必须是对象若已有值不是对象即使源值是对象也会整体覆盖这与官方文档注释#5402描述的“all other values are overwritten as usual”一致。若目标对象中该键不存在则直接插入源值含嵌套对象不会无谓递归。此外update被调用在一个null值上时会先把null转为空对象见 include/nlohmann/json.hpp这与push_back的null转换策略保持一致。工程场景默认配置与用户配置合并这是 update.md 给出的典型用例。应用默认设置如下{ color: red, active: true, name: {de: Maus, en: mouse} }用户选择性覆盖{ color: blue, name: {es: ratón} }先浅合并再深合并分别得到auto user_settings json::parse(config.json); auto effective_settings get_default_settings(); effective_settings.update(user_settings); // 默认浅合并重复键整体覆盖 // effective_settings.update(user_settings, true); // 深合并对象键逐层合并默认合并结果name被整体替换为{es: ratón}de/en丢失active因用户未设置而保留。深合并结果merge_objects truename变为{de: Maus, en: mouse, es: ratón}。update 的边界条件与语义摘要类型约束只能在对象上调用对非对象抛出type_error.312cannot use update() with string。区间版额外要求first与last属于同一 JSON 对象否则抛出invalid_iterator.210iterators do not fit。复杂度两种重载均为 O(N·log(size()N))N 为待插入元素个数。异常安全basic guarantee——若中途抛出异常值可能被部分修改。版本update自 3.0.0 加入merge_objects参数在 3.10.5 引入。使用ordered_json时向对象添加成员可能触发重新分配使全部迭代器与引用失效。update 与其他合并机制的边界update负责“把另一个完整对象合进来”。如果你需要的是结构化的差异修改nlohmann/json 还提供两条更规范的路径官方文档分别有独立专题详见文末延伸阅读JSON Merge PatchRFC 7386把“待修改补丁”整体应用到一个文档上天然是递归合并语义与update(obj, true)的应用目标互补patch 中显式置null表示删除键。JSON PatchRFC 6902用一系列明确定义的编辑操作add/remove/replace/move/copy/test配合json_pointer定位并修改文档。删除元素erase 的多种形态删除元素由erase完成它按调用目标与参数形态共有 5 组重载// (1) 按迭代器删除单个元素 iterator erase(iterator pos); const_iterator erase(const_iterator pos); // (2) 按迭代器区间删除 [first, last) iterator erase(iterator first, iterator last); // (3) 按键删除对象成员 size_type erase(const typename object_t::key_type key); // (4) 透明比较器按键删除3.11.0可与 string_view 等键类型比较 templatetypename KeyType size_type erase(KeyType key); // (5) 按下标删除数组元素 void erase(const size_type idx);官方示例给出最常用的两种形态json j {{a, 1}, {b, 2}, {c, 3}}; j.erase(b); // {a:1,c:3} json a {1, 2, 3, 4}; a.erase(1); // [1,3,4] (erase by index)各形态的关键语义按键 (3)/(4)仅对象可用返回值是实际删除的元素个数默认object_t为std::map时恒为 0 或 1。透明比较版本允许传入std::string_view之类的键类型而避免临时std::string构造C17。按下标 (5)仅数组可用复杂度与被删元素到数组末尾的距离成线性后续元素需前移下标越界idx size()抛出out_of_range.401如array index 17 is out of range。按迭代器 (1)/(2)可用在数组、对象等上pos必须是有效且可解引用的迭代器不能是end()。特别地如果在除null外的原始类型primitive如number/string上调用迭代器版值会被置为null——这是该接口为保持统一返回迭代器语义而做出的行为使用时需留意。对null调用任何形态都会抛出type_error.307cannot use erase() with null迭代器不属于当前值则抛invalid_iterator系列异常202/203/204/205。异常安全strong guarantee异常时原值保持完好。迭代器失效对象按迭代器/键删除会失效被删元素相关的引用与迭代器数组按迭代器删除会使被删位置及之后的迭代器、引用含end()失效。对应可运行示例包括 examples/erase__IteratorType.cpp、examples/erase__object_t_key_type.cpp 与 examples/erase__size_type.cpp。清空但保留类型clearclear的语义与erase不同它清空内容但保留当前 JSON 类型并把值重置为该类型的“默认值”等价于*this basic_json(type())void clear() noexcept;当前类型clear 后的值nullnullbooleanfalsestringnumber0binary空字节数组object{}array[]该函数声明为noexcept实现见 single_include/nlohmann/json.hpp 对应入口官方文档标注其具有不抛异常保证no-throw guarantee复杂度为 O(size)。注意它会失效与该值相关的全部迭代器、指针与引用。典型用途是把已用过的数组/对象“掏空复用”而不改变其在父结构中的位置与类型例如清空一个日志缓冲数组使其继续保持数组类型、可被再次push_back。如何把这些修改接口组合使用综合示例可直接编译运行#include iostream #include nlohmann/json.hpp using json nlohmann::json; int main() { json doc json::object(); // 显式创建对象 // 数组从 null 起步逐条追加 json tags; tags.emplace_back(cpp); tags json; doc[tags] std::move(tags); // 移入避免拷贝 // 对象仅在缺失时插入默认值 doc.emplace(retries, 3); // 合并把一段用户覆盖合入默认配置深合并 json defaults {{retries, 5}, {name, {en, default}}}; doc.update(defaults, false); // 已有键被覆盖 doc.update(R({name:{zh:示例}})_json, true); // 递归合并 name // 删除与清空 doc.erase(retries); // 按键删除 doc[tags].clear(); // 清空但保持数组类型 std::cout doc.dump(2) \n; // 输出剩余结构 }工程实践中几条建议构建大数组时优先emplace_back/而非反复operator[]代码更贴近“顺序追加”语义“add if absent”务必用emplace而非先查后写既省一次查找又天然线程内原子单线程下合并配置时先想清楚要浅合并还是深合并update第二参数merge_objects是浅/深的分水岭若要长期持有对成员对象的引用如auto x j[cfg];后续对该父对象执行插入/删除前要意识到可能引发的失效大范围的批量差异修改优先考虑 JSON Merge Patch 与 JSON Patch而不是手写多行eraseupdate。延伸阅读创建值创建对象、数组、字面量_json等基础见 creating_values只读取值见 element access 与 basic_json API 总览各接口 API 参考push_back、emplace_back、emplace、update、erase、clear结构化批量修改JSON Merge Patch 与 JSON Patch Diff、json_pointer修改类接口的实现集中位于 include/nlohmann/json.hppupdate/erase/clear同处该文件单头版本见 single_include/nlohmann/json.hpp相关单元测试可在 tests/src/unit-modifiers.cpp 中探索。【免费下载链接】jsonJSON for Modern C项目地址: https://gitcode.com/GitHub_Trending/js/json创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/11/4 12:41:46

基于NB-IoT与Qt的工业采集终端设计与实现要点解析

前阵子一个老同事打电话问我:你们那套“中国移动NB-IoT QT采集终端”,到底是怎么个做法?我缓了一下才意识到,这个项目名其实已经把关键技术路线全说清楚了——NB-IoT决定它跟外界通信的通道,QT决定了终端侧软件用什么框…

2026/11/4 12:22:26

NB-IoT采集终端与Qt上位机开发实战:从串口通信到FFT频谱分析

做嵌入式的人都知道,这两年NB-IoT几乎是远程采集类项目的默认答案。低功耗、广覆盖、室内深覆盖能力强,一块电池跑几年,专门为物联网碎片化场景设计。我去年接手了一个中国移动NB-IoT QT采集终端的项目,说白了就是做一个既能本地采…

2026/10/26 23:32:31

阿里云大数据产品体系解析:从数据接入到应用全链路实践

如果你刚好准备用阿里云这颗大树来搭大数据体系,打开产品列表那一刻大概率会懵一下:MaxCompute、DataWorks、Hologres、Flink、EMR、ADB……光名字都够背一阵子。我在阿里云上从零折腾数据仓库和数据平台这几年,最大的体会是:这些…

2026/11/4 12:41:08

大数据产品技术架构与行业应用解析

1. 大数据领域数据产品的发展现状剖析 1.1 行业应用全景扫描 在金融行业,数据产品已经深度嵌入核心业务流程。以某股份制商业银行的智能风控系统为例,其通过整合内部交易数据、外部征信数据和社交行为数据,将传统风控模型的审批时效从3天缩短…

2026/11/4 12:41:08

2kg手提电子秤设计方案:电阻应变式传感器与ICL7107链路解析

简介:围绕电阻应变式传感器电子秤设计的课程设计文档,面向电子信息、自动化等专业学生及刚接触传感器测量的开发者,重点解决2kg手提电子秤从称重传感、信号调理到数字显示的完整方案设计问题。文档以电阻应变片和桥式测量电路为核心&#xff…

2026/11/4 12:41:08

时间区间重叠判断算法与工程实践

1. 时间区间重叠判断的核心逻辑 时间区间重叠判断是日程管理、资源调度、会议安排等场景中的基础需求。想象一下会议室预定系统:当有人想预定某个时间段时,系统需要快速判断该时段是否已被占用。这种判断本质上就是检测两个时间区间是否存在交集。 判断…

2026/11/4 12:41:08

iOS开发中ATS安全机制与调试技巧详解

1. iOS网络请求安全机制解析 在iOS应用开发中,App Transport Security(ATS)是苹果从iOS 9开始引入的重要安全特性。这套机制强制要求所有网络通信必须使用HTTPS协议,并且对TLS版本和加密算法提出了严格要求。ATS的默认配置会拦截所有不符合安全标准的HTT…

2026/11/4 12:41:08

分布式系统架构核心挑战与实践指南

1. 分布式系统架构的本质与核心挑战 第一次接触分布式系统时,我被各种晦涩的概念弄得晕头转向。直到自己真正参与设计了一个日均处理10亿请求的电商平台架构,才理解分布式系统本质上是通过网络连接的多个计算节点协同工作,对外表现为一个整体…

2026/11/4 12:36:08

ISO/IEC 42001草案解读:AI管理体系PDCA与双评估落地

简介:ISO/IEC DIS 42001:2022(draft)是信息技术—人工智能—管理体系方向的国际标准草案英文文本,面向 AI 合规、算法治理、信息安全及体系认证相关的从业者、企业管理者和标准研究者。草案围绕人工智能管理系统的组织与职责划分、…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

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

2026/11/4 0:03:20

AI辅助技术栈评估:提升研发决策效率60%

1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年…

2026/11/4 0:03:20

从生成Token到直接决策:Jev如何重塑AI Agent工程实践

1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你…

2026/11/4 0:03:20

32G统一内存跑大模型:内存账、TPS实测与端云分流

想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

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

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑