使用rapidjson::Writer触发!hasRoot_断言错误及代码正确性咨询
问题:RapidJSON Writer生成分段JSON数组触发断言错误
需求是将myMap中的条目转换为多个大小约10KB的JSON数组,使用rapidjson::Writer和rapidjson::StringBuffer实现时,触发断言错误(writer.h第488行,!hasRoot_断言失败)。
代码示例
rapidjson::StringBuffer s; rapidjson::Writer<rapidjson::StringBuffer> writer(s); writer.StartArray(); for (auto itr = myMap.begin(); itr != myMap.end(); itr++) { writer.StartObject(); writer.Key(itr->first.c_str()); writer.String(itr->second.c_str()); writer.EndObject(); if (cond_matches) { writer.EndArray(); Process( s.GetString() ); s.Clear(); writer.Reset(s); // 不加这行的话,下一行会触发断言错误 writer.StartArray(); // 开启新的记录数组 } }
报错信息
../include/rapidjson/writer.h:488: void rapidjson::Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags>::Prefix(rapidjson::Type) [with OutputStream = rapidjson::GenericStringBuffer<rapidjson::UTF8<> >; SourceEncoding = rapidjson::UTF8<>; TargetEncoding = rapidjson::UTF8<>; StackAllocator = rapidjson::CrtAllocator; unsigned int writeFlags = 0]: Assertion `!hasRoot_' failed.
问题原因与解决
断言错误的原因
hasRoot_是RapidJSON Writer内部的状态标记,用于记录当前是否已创建根节点(数组或对象)。调用writer.EndArray()后,hasRoot_会被置为false,但Writer的内部栈等状态并未完全重置。如果仅清空StringBuffer而不重置Writer,直接调用writer.StartArray()时,Writer的内部状态可能残留之前的上下文,导致!hasRoot_断言检查失败。
已验证的解决方法
添加writer.Reset(s)是正确操作——该方法会完全重置Writer的内部状态(包括栈、hasRoot_标记等),并重新关联清空后的StringBuffer,确保后续StartArray()能正常创建新的根数组。
代码潜在bug检查
目前核心逻辑已解决断言问题,但仍有几个需要注意的点:
- 收尾处理缺失:循环结束后,可能还有未处理的剩余元素留在当前数组中,需额外判断并调用
writer.EndArray()和Process()处理最后一批数据,避免丢失记录。 - 大小判断精度:
cond_matches的逻辑如果仅依据当前缓冲区大小,需考虑JSON结构的额外开销(比如数组括号、对象括号、逗号分隔符等),建议在添加元素前预估大小,避免生成的JSON超出10KB过多。 - 字符串有效性:
itr->first.c_str()和itr->second.c_str()在调用writer.Key()和writer.String()时是有效的(循环中直接使用map迭代器元素),这部分无需额外处理。
内容的提问来源于stack exchange,提问作者Hegde
相关产品推荐
相关产品推荐

