RapidJSON合并Document前必须先确认两者均为对象类型,否则会触发断言失败或崩溃;CopyFrom仅浅层覆盖而非合并,深层合并需手动递归实现并严格校验类型与内存分配器。

合并前先确认两个Document是否为对象类型
直接调用 CopyFrom 或 Move 合并时,如果任一 Document 不是 ObjectType(比如是数组、字符串或 null),会触发断言失败或未定义行为。RapidJSON 不自动转换类型,也不报清晰错误——它可能静默失败或崩溃。
- 务必在合并前检查:
doc1.IsObject() && doc2.IsObject() - 若源数据来自解析(如
Parse()),确保解析成功且无错误:if (doc.Parse(json_str).HasParseError()) { ... } - 不要假设输入“肯定是 object”——API 响应、配置文件、用户输入都可能返回
[]或null
用CopyFrom逐字段合并,而非覆盖整个Document
CopyFrom 是最安全的合并方式,它把 doc2 的每个成员复制到 doc1 中,支持同名键覆盖(后写入的值生效)。但注意:它只作用于当前层级,不递归合并嵌套对象。
- 示例:
for (auto& m : doc2.GetObject()) { doc1.AddMember(m.name, m.value, doc1.GetAllocator()); }更直观,但需手动处理内存分配器 - 推荐写法:
doc1.CopyFrom(doc2, doc1.GetAllocator());—— 这会清空doc1并完全替换为doc2的内容,不是“合并”而是“赋值” - 真正合并需遍历:
for (auto& m : doc2.GetObject()) { doc1.AddMember(m.name, m.value, doc1.GetAllocator()); },且要提前判断键是否存在,否则重复AddMember会失败
深层嵌套对象需要手写递归合并逻辑
RapidJSON 没有内置 deep merge 函数。如果 doc1 和 doc2 都有 "config": { "timeout": 30, "retries": 3 },而你想让 doc2 只覆盖 timeout、保留 retries,就必须自己递归处理。
- 关键点:对每个同名键,检查双方是否都为
Object;若是,进入递归;否则直接覆盖 - 注意内存管理:每次调用
AddMember或CopyFrom都依赖Allocator,跨层级传递时别传错实例 - 避免循环引用误判:RapidJSON 不检测 JSON 循环结构,深层递归前建议加深度限制(如 >10 层就 abort)
合并后记得验证Document有效性并重用Allocator
合并操作可能因内存不足或非法值(如 NaN、Infinity)导致内部状态异常,但 Document 仍可能显示为 “valid”,直到你尝试序列化才 crash。
立即学习“C++免费学习笔记(深入)”;
- 序列化前做一次轻量检查:
StringBuffer buffer; Writer<stringbuffer> writer(buffer); doc1.Accept(writer);</stringbuffer>,捕获异常或检查buffer.Length()是否合理 -
Allocator是非线程安全的,且不能在不同Document间混用;合并中所有AddMember/CopyFrom必须用目标文档的GetAllocator() - 常见坑:把临时
Document(如解析中间结果)的Allocator传给主文档,导致后续AddMember写入野内存
深层合并没有银弹,RapidJSON 提供的是构件,不是开箱即用的 merge 工具。最容易被忽略的是:你以为在“合并对象”,实际可能在反复构造新 Value 而没释放旧内存,尤其在循环中频繁调用时,Allocator 的 chunk 分配策略会让泄漏不明显但持续增长。


















