如何修复构建嵌套 Documents 时 RapidJSON 的段错误
问题:
你想构建一个 RapidJSON 应用程序,从零开始构建 JSON 并使用嵌套在其他文档中的 Documents,但当你尝试运行它时,你看到类似这样的错误消息
output.txt
zsh: segmentation fault (core dumped) ./rapidjson-example解决方案
段错误(即非法内存访问)可能有很多原因,但最常见的是你使用了局部分配器。
为了修复此问题,为你的整个应用程序使用一个分配器。
allocator_example.cpp
MemoryPoolAllocator<> jsonAlloc; // 我建议静态声明此变量
// ...
doc.AddMember("text", Value().SetString("Hello JSON!"), jsonAlloc);注意 MemoryPoolAllocator 从不释放其内存池中的任何内存。
解释:
许多 RapidJSON 示例告诉你使用类似这样的调用
rapidjson_local_allocator_example.cpp
Document d;
doc.AddMember("text", ... , doc.GetAllocator());但始终使用 doc.GetAllocator() 的方法只适用于非常简单的示例。
段错误的原因似乎是一旦 Document 超出作用域,其分配器实例就会被释放,因此内存将被重用。但是,到目前为止我没有进一步追踪此问题。
复现问题的最小示例:
rapidjson_repro.cpp
#include <iostream>
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/ostreamwrapper.h>
using namespace rapidjson;
using namespace std;
Document generateInnerDoc() {
// 生成文档:{"text": "Hello JSON!"}
Document doc;
doc.SetObject(); // 使 doc 成为对象!
// 通过 SetString() 强制分配
doc.AddMember("text", Value().SetString("Hello JSON!"), doc.GetAllocator());
return doc;
}
Document generateOuterDoc() {
// 生成文档:{"text": "Hello JSON!"}
Document doc;
doc.SetObject();
doc.AddMember("text", generateInnerDoc(), doc.GetAllocator());
return doc;
}
int main() {
// Write to stdout
OStreamWrapper out(cout);
// Write document...
Writer<OStreamWrapper> writer(out);
generateOuterDoc().Accept(writer);
}修复后的示例:
rapidjson_fixed.cpp
#include <iostream>
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/ostreamwrapper.h>
using namespace rapidjson;
using namespace std;
MemoryPoolAllocator<> jsonAlloc;
Document generateInnerDoc() {
// 生成文档:{"text": "Hello JSON!"}
Document doc;
doc.SetObject(); // 使 doc 成为对象!
// 通过 SetString() 强制分配
doc.AddMember("text", Value().SetString("Hello JSON!"), jsonAlloc);
return doc;
}
Document generateOuterDoc() {
// 生成文档:{"text": "Hello JSON!"}
Document doc;
doc.SetObject(); // 使 doc 成为对象!
// 通过 SetString() 强制分配
doc.AddMember("text", generateInnerDoc(), jsonAlloc);
return doc;
}
int main() {
// Write to stdout
OStreamWrapper out(cout);
// Write document...
Writer<OStreamWrapper> writer(out);
generateOuterDoc().Accept(writer);
}Check out similar posts by category:
C/C++
If this post helped you, please consider buying me a coffee or donating via PayPal to support research & publishing of new posts on TechOverflow