11. 示例 4 :读数组 8

12. 示例 5: Writer 构造一个 json ,然后修改它,最后转成字符串 9

13. 示例 6: Document 构造一个 json ,然后修改它,最后转成字符串 10

14. 示例 7: Document 构造一个 json ,然后修改它,最后转成字符串 12

15. 示例 8 :构造空对象和数组 12

16. 示例 9 :删除数组元素 13

17. 示例 10 :不转义中文 14

18. 示例 11 schema 使用示例 15

19. 示例 12 schema 完整示例 17

20. FindMember 整数值 18

21. FindMember 字符串值 18

22. 遍历成员 18

23. 遍历数组 1 :字符串数组 19

24. 遍历数组 2 :一级对象数组 19

25. 遍历数组 3 :两级对象数组 20

26. 辅助函数 1 :任意类型都以字符串返回 20

27. 辅助函数 2 :取 int32_t 22

28. 辅助函数 3 :取 int64_t 22

29. 辅助函数 4 :取 uint32_t 23

30. 辅助函数 5 :取 uint64_t 23

31. 辅助函数 6 :对象转字符串 24

32. 辅助函数 7 :字符串转对象 24

33. rapidjson 的“坑” 25

1. 前言

rapidjson 相比 jsoncpp 性能高出太多,使用接口一样的简单的。官方中文帮助文档: http://rapidjson.org/zh-cn/

2. Move 语意

rapidjson Move 语意,请浏览

http://rapidjson.org/zh-cn/md_doc_tutorial_8zh-cn.html#MoveSemantics

rapidjson 为了最大化性能,大量使用了浅拷贝,使用之前一定要了解清楚。如果采用了浅拷贝,特别要注意局部对象的使用,以防止对象已被析构了,却还在被使用。

3. rapidjson::Document

特别注意 rapidjson::Document 可以为 object 、array、number、string、boolean和null 中任意一种类型 只有为 object 时才可以调用 HasMember 等与 object 有关的方法

#include <rapidjson/document.h>

#include <rapidjson/error/en.h>

#include <rapidjson/stringbuffer.h>

#include <rapidjson/writer.h>

#include <stdio.h>

int main(int argc, char* argv[])

std::string str;

rapidjson::Document doc;

doc.Parse(argv[1]);

if (doc.HasParseError())

printf("parse error\n");

// 注意doc可为object, array, number, string, boolean, null中任意一种类型

if (!doc.IsObject())

printf("not object\n");

printf("parse ok\n");

if (doc.IsNumber())

printf("%d\n", doc.GetInt());

// doc为object类型时,才能调用HasMember

if (doc.HasMember("x"))

printf("has x\n");

printf("without x\n");

return 0;

rapidjson::Document doc;

for (int i=0; i<1000000; ++i) {

std::string a = "{\"b\":1" + std::to_string(i) + "}";

doc. Parse (a.c_str());

return 0;

rapidjson::Document doc;

for (int i=0; i<1000000; ++i) {

std::string a = "{\"b\":1" + std::to_string(i) + "}";

doc. Parse (a.c_str());

rapidjson::Document tmpdoc;

doc. Swap (tmpdoc);

return 0;

2) 使用 Value 类型指针

Document 类型指针当 Value 类型指针使用,出现内存泄漏,原因是 Value 的析构不是虚拟的 ,打开 -Wall 编译器也不会告警

5. 成员迭代器 MemberIterator

成员迭代器 rapidjson::Value:: MemberIterator 实际指向 GenericMember

GenericValue<Encoding, Allocator> name ;

// 成员值,可为各类类型,如字符串、数组、子对象等

GenericValue<Encoding, Allocator> value ;

typedef typename GenericMemberIterator <false,Encoding,Allocator>::Iterator MemberIterator ;

class GenericMemberIterator {

typedef GenericMember <Encoding,Allocator> PlainType;

typedef typename internal::MaybeAddConst<Const, PlainType >::Type ValueType ;

typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType ;

typedef GenericMemberIterator Iterator;

// Pointer to (const) GenericMember

typedef typename BaseType::pointer Pointer ;

Pointer ptr_; // raw pointer

Pointer operator-> () const { return ptr_; }

#include <rapidjson/document.h>

#include <rapidjson/error/en.h>

#include <rapidjson/stringbuffer.h>

#include <rapidjson/writer.h>

rapidjson::Document document; // 定义一个Document对象

std::string str = "{\"count\":2,\"names\":[\"zhangsan\",\"wangwu\"]}";

document.Parse(str.c_str()); // 解析,Parse()无返回值,也不会抛异常

if (document.HasParseError()) // 通过HasParseError()来判断解析是否成功

// 可通过GetParseError()取得出错代码,

// 注意GetParseError()返回的是一个rapidjson::ParseErrorCode类型的枚举值

// 使用函数rapidjson::GetParseError_En()得到错误码的字符串说明,这里的En为English简写

// 函数GetErrorOffset()返回出错发生的位置

printf("parse error: (%d:%d)%s\n", document.GetParseError(), document.GetErrorOffset(), rapidjson::GetParseError_En(document.GetParseError()));

// 判断某成员是否存在

if (!document.HasMember("count") || !document.HasMember("names"))

printf("invalid format: %s\n", str.c_str());

// 如果count不存在,则运行程序会挂,DEBUG模式下直接abort

rapidjson::Value& count_json = document["count"];

// 如果count不是整数类型,调用也会挂,DEBUG模式下直接abort

// GetInt()返回类型为int

// GetUint()返回类型为unsigned int

// GetInt64()返回类型为int64_t

// GetUint64()返回类型为uint64_t

// GetDouble()返回类型为double

// GetString()返回类型为char*

// GetBool()返回类型为bool

int count = count_json.GetInt();

printf("count=%d\n", count);

// 方法GetType()返回枚举值: kNullType,kFalseType,kTrueType,kObjectType,kArrayType,kStringType,kNumberType

// 可用IsArray()判断是否为数组,示例: { "a": [1, 2, 3, 4] }

// 用IsString()判断是否为字符串值

// 用IsDouble()判断是否为double类型的值,示例: { "pi": 3.1416 }

// 用IsInt()判断是否为int类型的值

// 用IsUint()判断是否为unsigned int类型的值

// 用IsInt64()判断是否为int64_t类型的值

// 用IsUint64()判断是否为uint64_t类型的值

// 用IsBool()判断是否为bool类型的值

// 用IsFalse()判断值是否为false,示例: { "t": true, "f": false }

// 用IsTrue()判断值是否为true

// 用IsNull()判断值是否为NULL,示例: { "n": null }

// 更多说明可浏览:

// https://miloyip.gitbooks.io/rapidjson/content/zh-cn/doc/tutorial.zh-cn.html

const rapidjson::Value& names_json = document["names"];

for (rapidjson::SizeType i=0; i<names_json.Size(); ++i)

std::string name = names_json[i].GetString();

printf("name=%s\n", name.c_str());

rapidjson::StringBuffer buffer;

rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

writer.StartObject();

// count

writer.Key("count");

writer.Int(2);

// 写4字节有符号整数: Int(int32_t x)

// 写4字节无符号整数: Uint(uint32_t x)

// 写8字节有符号整数: Int64(int64_t x)

// 写8字节无符号整数: Uint64(uint64_t x)

// 写double值: Double(double x)

// 写bool值: Bool(bool x)

// names

writer.Key("names");

writer.StartArray();

writer.StartObject();

writer.Key("name");

writer.String("zhangsan");

writer.EndObject();

writer.StartObject();

writer.Key("name");

writer.String("wangwu");

writer.EndObject();

writer.EndArray();

writer.EndObject();

// 以字符串形式打印输出

printf("%s\n", buffer.GetString());

rapidjson::Document document;

std::string str = "{\"name\":\"zhangsan\",\"age\":20}";

document.Parse(str.c_str());

rapidjson::Value& name_json = document["name"];

rapidjson::Value& age_json = document["age"];

std::string new_name = "wangwu";

int new_age = 22;

// 注意第三个参数是document.GetAllocator(),相当于深拷贝,rapidjson会分配一块内存,然后复制new_name.c_str(),

// 如果不指定第三个参数,则是浅拷贝,也就是rapidjson不会分配一块内存,而是直接指向new_name.c_str(),省去复制提升了性能

// 官方说明:

// http://rapidjson.org/zh-cn/md_doc_tutorial_8zh-cn.html#CreateString

name_json.SetString(new_name.c_str(), new_name.size(), document.GetAllocator());

age_json.SetInt(new_age);

// 转成字符串输出

rapidjson::StringBuffer buffer;

rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

document.Accept(writer);

printf("%s\n", buffer.GetString());

rapidjson::Document document;

std::string str = "{\"count\":2,\"names\":[{\"name\":\"zhangsan\"},{\"name\":\"wangwu\"}]}";

document.Parse(str.c_str());

if (document.HasParseError())

printf("parse error: %d\n", document.GetParseError());

rapidjson::Value& names_json = document["names"];

for (rapidjson::SizeType i=0; i<names_json.Size(); ++i)

if (names_json[i].HasMember("name"))

rapidjson::Value& name_json = names_json[i]["name"];

printf("%s ", name_json.GetString());

printf("\n");

rapidjson::StringBuffer buffer1;

rapidjson::Writer<rapidjson::StringBuffer> writer1(buffer1);

writer1.StartObject();

writer1.Key("count");

writer1.Int(2);

writer1.EndObject();

printf("%s\n", buffer1.GetString());

// 转成Document对象

rapidjson::Document document;

document.Parse(buffer1.GetString());

// 修改

rapidjson::Value& count_json = document["count"];

count_json.SetInt(8);

// 转成字符串

rapidjson::StringBuffer buffer2;

rapidjson::Writer<rapidjson::StringBuffer> writer2(buffer2);

document.Accept(writer2);

printf("%s\n", buffer2.GetString());

rapidjson::Document document;

std::string str = "{}"; // 这个是必须的,且不能为"",否则Parse出错

document.Parse(str.c_str());

// 新增成员count

// AddMember第一个参数可以为字符串常,如“str”,不能为“const char*”和“std::string”,

// 如果使用“const char*”,则需要使用StringRefType转换:StringRefType(str.c_str())

document.AddMember("count", 3, document.GetAllocator());

// 新增数组成员

rapidjson::Value array(rapidjson::kArrayType);

rapidjson::Value object(rapidjson::kObjectType); // 数组成员

object.AddMember("id", 1, document.GetAllocator());

object.AddMember("name", "zhangsan", document.GetAllocator());

// 如果数组添加无名字的成员,定义Value时应当改成相应的类型,如:

//rapidjson::Value value(rapidjson::kStringType);

//rapidjson::Value value(rapidjson::kNumberType);

//rapidjson::Value value(rapidjson::kFalseType);

//rapidjson::Value value(rapidjson::kTrueType);

//array.PushBack(value, document.GetAllocator());

//效果将是这样:'array':[1,2,3,4,5]

// 注意下面用法编译不过:

//std::string str1 = "hello";

//object.AddMember("name", str1.c_str(), document.GetAllocator());

//const char* str2 = "hello";

//object.AddMember("name", str2, document.GetAllocator());

// 下面这样可以:

//object.AddMember("name", "hello", document.GetAllocator());

//const char str3[] = "hello";

//object.AddMember("name", str3, document.GetAllocator());

//std::string str4 = "#####";

//rapidjson::Value v(str4.c_str(), document.GetAllocator());

//obj.AddMember("x", v, document.GetAllocator());

// 上面两行也可以写在一行:

//obj.AddMember("x", rapidjson::Value(str4.c_str(), document.GetAllocator()).Move(), document.GetAllocator());

// 添加到数组中

array.PushBack(object, document.GetAllocator());

// 添加到document中

document.AddMember("names", array, document.GetAllocator());

// 转成字符串输出

rapidjson::StringBuffer buffer1;

rapidjson::Writer<rapidjson::StringBuffer> writer1(buffer1);

document.Accept(writer1);

printf("%s\n", buffer1.GetString());

// 修改值

rapidjson::Value& count_json = document["count"];

count_json.SetInt(9);

// 再次输出

rapidjson::StringBuffer buffer2;

rapidjson::Writer<rapidjson::StringBuffer> writer2(buffer2);

document.Accept(writer2);

printf("%s\n", buffer2.GetString());

std::string title = "\u8D2B\u56F0\u5B64\u513F\u52A9\u517B";

document.AddMember("title", rapidjson::Value(title.c_str(), document.GetAllocator()).Move(), document.GetAllocator());

rapidjson::StringBuffer buffer;

rapidjson::Writer<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::ASCII<> > writer(buffer);

// 如果上面一句改成普通的:

// rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

// 则输出将变成:

// x7=>

// 贫困孤儿助养

document.Accept(writer);

printf("x7=>\n%s\n", buffer.GetString());

// 下面为2种构造空对象的方法

document.AddMember("age", rapidjson::Value(rapidjson::kObjectType).Move(), document.GetAllocator());

document.AddMember("times", rapidjson::Value().SetObject(), document.GetAllocator());

// 下面为2种构造空数组的方法

document.AddMember("names", rapidjson::Value(rapidjson::kArrayType).Move(), document.GetAllocator());

document.AddMember("urls", rapidjson::Value(rapidjson::kArrayType).Move(), document.GetAllocator());

document.AddMember("books", rapidjson::Value().SetArray(), document.GetAllocator());

rapidjson::StringBuffer buffer1;

rapidjson::Writer<rapidjson::StringBuffer> writer1(buffer1);

document.Accept(writer1);

printf("%s\n", buffer1.GetString());

rapidjson::Value& age = document["age"];

age.SetInt(6);

rapidjson::StringBuffer buffer2;

rapidjson::Writer<rapidjson::StringBuffer> writer2(buffer2);

document.Accept(writer2);

printf("%s\n", buffer2.GetString());

{ "names": [ {"name":"zhangsan","age":100}, {"name":"wangwu","age":90}, {"name":"xiaozhang","age":20} ]}

{"names":[{"name":"zhangsan","age":100},{"name":"wangwu","age":90}]}

void x9()

std::string str = "{ \"names\": [ {\"name\":\"zhangsan\",\"age\":100}, {\"name\":\"wangwu\",\"age\":90}, {\"name\":\"xiaozhang\",\"age\":20} ]}";

rapidjson::Document document;

document.Parse(str.c_str());

rapidjson::Value& names_json = document["names"];

for (rapidjson::Value::ValueIterator iter=names_json.Begin(); iter!=names_json.End();)

std::string name = (*iter)["name"].GetString();

// 不要小张了

if (name == "xiaozhang")

iter = names_json.Erase(iter);

++iter;

rapidjson::StringBuffer buffer;

rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

document.Accept(writer);

printf("%s\n", str.c_str());

printf("%s\n", buffer.GetString());

//g++ -g -o b b.cpp -I/usr/local/thirdparty/rapidjson/include

#include <rapidjson/document.h>

#include <rapidjson/stringbuffer.h>

#include <rapidjson/writer.h>

#include <string>

#include <stdio.h>

int main()

std::string str = "{\"title\":\"\u8d2b\u56f0\u5b64\u513f\u52a9\u517b\"}";

rapidjson::Document document;

document.Parse(str.c_str());

if (document.HasParseError())

printf("parse %s failed\n", str.c_str());

exit(1);

rapidjson::StringBuffer buffer1;

rapidjson::Writer<rapidjson::StringBuffer> writer1(buffer1);

document.Accept(writer1);

printf("%s\n", buffer1.GetString());

rapidjson::StringBuffer buffer2;

rapidjson::Writer<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::ASCII<> > writer2(buffer2);

document.Accept(writer2);

printf("%s\n", buffer2.GetString());

return 0;

SchemaDocument schema(schema_document);

SchemaValidator validator(schema);

if (!document. Accept (validator))

// 检验出错,输出错误信息

StringBuffer sb;

validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);

printf("Invalid schema: %s\n", sb.GetString());

printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());

sb.Clear();

validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);

printf("Invalid document: %s\n", sb.GetString());

"$schema": "http://json-schema.org/draft-04/schema#",

"title": "Product",

"description": "A product from Acme's catalog",

"type": "object",

"properties": {

"id": {

"description": "The unique identifier for a product",

"type": "integer"

"name": {

"description": "Name of the product",

"type": "string"

"price": {

"type": "number",

"minimum": 0,

"exclusiveMinimum": true

"tags": {

"type": "array",

"items": {

"type": "string"

"minItems": 1,

"uniqueItems": true

"required": ["id", "name", "price"]

#include <rapidjson/document.h>

#include <rapidjson/schema.h>

#include <rapidjson/stringbuffer.h>

int main()

std::string str = "\{\"aaa\":111,\"aaa\":222}"; // "\{\"aaa\":111,\"a\":222}"

#if 0

std::string schema_str = "{\"type\":\"object\",\"properties\":{\"aaa\":{\"type\":\"integer\"},\"bbb\":{\"type\":\"string\"}},\"required\":[\"aaa\",\"bbb\"]}";

#else

std::string schema_str = "{\"type\":\"object\",\"properties\":{\"aaa\":{\"type\":\"integer\"},\"bbb\":{\"type\":\"integer\"}},\"required\":[\"aaa\",\"bbb\"]}";

#endif

printf("%s\n", str.c_str());

printf("%s\n", schema_str.c_str());

rapidjson::Document doc;

rapidjson::Document schema_doc;

schema_doc.Parse(schema_str.c_str());

doc.Parse(str.c_str());

rapidjson:: SchemaDocument schema(schema_doc);

rapidjson:: SchemaValidator validator(schema);

if (doc. Accept (validator))

printf("data ok\n");

rapidjson:: StringBuffer sb;

validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);

printf("Invalid schema: %s\n", sb.GetString());

printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());

sb.Clear();

validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);

printf("Invalid document: %s\n", sb.GetString());

return 0;

const rapidjson::Value::ConstMemberIterator iter =

doc.FindMember("age");

if (iter!=doc.MemberEnd() && iter->value. IsInt ())

age = iter->value. GetInt ();

std::string name;

const rapidjson::Value::ConstMemberIterator iter =

doc.FindMember("name");

if (iter!=doc.MemberEnd() && iter->value. IsString ())

name.assign(iter->value. GetString (), iter->value. GetStringLength ());

rapidjson::Value value;

for (rapidjson::Value::ConstMemberIterator iter=value.MemberBegin();

iter!=value.MemberEnd(); ++iter)

const rapidjson::Value& name_json = iter->name; // 这个必是 字符串

const rapidjson::Value& value_json = iter->value; // 这个可以为对象、数组等

printf("%s\n", name_json.GetString());

const rapidjson::Value& k = doc["k"];

// 遍历数组

for (rapidjson::Value::ConstValueIterator v_iter=k.Begin();

v_iter!=k.End(); ++v_iter)

// k1

// k2

// k3

printf("%s\n", (*v_iter).GetString());

const rapidjson::Value& h = doc["h"];

// 遍历数组

for (rapidjson::Value::ConstValueIterator v_iter=h.Begin();

v_iter!=h.End(); ++v_iter)

const rapidjson::Value& field = *v_iter;

for (rapidjson::Value::ConstMemberIterator m_iter=field.MemberBegin();

m_iter!=field.MemberEnd(); ++m_iter) // kf对

// k1 => f1

// k2 => f2

const char* key = m_iter->name.GetString();

const char* value = m_iter->value.GetString();

printf("%s => %s\n", key, value);

break;

// {"h":[{"k1":["f1","f2"]},{"k2":["f1","f2"]}]}

rapidjson::Document doc;

doc.Parse(str.c_str());

const rapidjson::Value& h = doc["h"];

// 遍历第一级数组

for (rapidjson::Value::ConstValueIterator v1_iter=h.Begin();

v1_iter!=h.End(); ++v1_iter)

const rapidjson::Value& k = *v1_iter; // k1,k2,k3

// 成员遍历

for (rapidjson::Value::ConstMemberIterator m_iter=k.MemberBegin();

m_iter!=k.MemberEnd(); ++m_iter)

const char* node_name = m_iter->name.GetString();

printf("hk: %s\n", node_name);

const rapidjson::Value& node = m_iter->value;

// 遍历第二级数组

for (rapidjson::Value::ConstValueIterator v2_iter=node.Begin();

v2_iter!=node.End(); ++v2_iter)

const char* field = (*v2_iter).GetString();

printf("field: %s\n", field); // f1,f2,f3

// 如果不存在,或者为数组则返回空字符串。

std::string rapidjson_string_value(rapidjson::Value& value, const std::string& name)

if (!value.HasMember(name.c_str()))

return std::string("");

const rapidjson::Value& child = value[name.c_str()];

if (child.IsString())

return child.GetString();

char str[100];

if (child.IsInt())

snprintf(str, sizeof(str), "%d", child.GetInt());

else if (child.IsInt64())

// 为使用PRId64,需要#include <inttypes.h>,

// 同时编译时需要定义宏__STDC_FORMAT_MACROS

snprintf(str, sizeof(str), "%"PRId64, child.GetInt64());

else if (child.IsUint())

snprintf(str, sizeof(str), "%u", child.GetUint());

else if (child.IsUint64())

snprintf(str, sizeof(str), "%"PRIu64, child.GetUint64());

else if (child.IsDouble())

snprintf(str, sizeof(str), "%.2lf", child.GetDouble());

else if (child.IsBool())

if (child.IsTrue())

strcpy(str, "true");

strcpy(str, "false");

str[0] = '\0';

return str;

// 当为int32_t值,或字符串实际为int32_t值时,返回对应的int32_t值,其它情况返回0

int32_t rapidjson_int32_value(rapidjson::Value& value, const std::string& name)

if (!value.HasMember(name.c_str()))

return 0;

const rapidjson::Value& child = value[name.c_str()];

if (child.IsInt())

return child.GetInt();

else if (child.IsString())

return atoi(child.GetString());

return 0;

int64_t rapidjson_int64_value(rapidjson::Value& value, const std::string& name)

if (!value.HasMember(name.c_str()))

return 0;

const rapidjson::Value& child = value[name.c_str()];

if (child.IsInt64())

return child.GetInt64();

else if (child.IsString())

return (int64_t)atoll(child.GetString());

return 0;

uint32_t rapidjson_uint32_value(rapidjson::Value& value, const std::string& name)

if (!value.HasMember(name.c_str()))

return 0;

const rapidjson::Value& child = value[name.c_str()];

if (child.IsUint())

return child.GetUint();

else if (child.IsString())

return (uint32_t)atoll(child.GetString());

return 0;

uint64_t rapidjson_uint64_value(rapidjson::Value& value, const std::string& name)

if (!value.HasMember(name.c_str()))

return 0;

const rapidjson::Value& child = value[name.c_str()];

if (child.IsUint64())

return child.GetUint64();

else if (child.IsString())

return (uint64_t)atoll(child.GetString());

return 0;

std::string& to_string (const rapidjson::Value& value, std::string* str)

rapidjson::StringBuffer buffer;

rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

value.Accept(writer);

str->assign(buffer.GetString(), buffer.GetSize());

return *str;

std::string to_string (const rapidjson::Value& value)

std::string str;

to_string(value, &str);

#if __cplusplus < 201103L

return str;

#else

return std::move(str);

#endif // __cplusplus < 201103L

bool to_rapidjson(const std::string& str, rapidjson::Document* doc)

doc->Parse(str.c_str());

return !doc->HasParseError();

void to_rapidjson(const std::string& str, rapidjson::Document& doc)

doc.Parse(str.c_str());

if (doc.HasParseError())

doc.Parse("{}");

33. rapidjson 的“坑”

使用不当,则会掉进 “坑”里。下列代码在 valgrind 中运行时,会报大量错误,而且如果 sub 是在一个循环中被 AddMember ,则无法得到预期的结果。

从现象看像是 sub 析构后仍在被使用,为验证这个推测,改成: rapidjson::Document* sub = new rapidjson::Document; ,然后再使用不但 valgrind 不报错,而且循环使用也没问题,那么可以肯定 AddMember 是浅拷贝,这样一来使用就不方便了,除非还有深拷贝的调用方式。

#include <rapidjson/schema.h>

#include <rapidjson/document.h>

#include <rapidjson/stringbuffer.h>

#include <rapidjson/writer.h>

#include <string>

#include <vector>

int main()

rapidjson::Document doc;

doc.Parse("{}");

{ // 目的是让sub在printf时已无效

rapidjson::Document sub;

sub.Parse("{\"name\":\"tom\"}");

doc.AddMember("sub", sub, doc.GetAllocator());

rapidjson::StringBuffer buffer;

rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

doc.Accept(writer);

printf("%s\n", buffer.GetString());

return 0;

==30425== Invalid read of size 2

==30425==    at 0x804B008: rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::IsString() const (document.h:947)

==30425==    by 0x8051632: bool rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::Accept<rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u> >(rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>&) const (document.h:1769)

==30425==    by 0x80488CE: main (f.cpp:30)

==30425==  Address 0x428eb62 is 58 bytes inside a block of size 65,548 free'd

==30425==    at 0x4023329: free (vg_replace_malloc.c:473)

==30425==    by 0x804BC72: rapidjson::CrtAllocator::Free(void*) (allocators.h:79)

==30425==    by 0x804BDD7: rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>::Clear() (allocators.h:148)

==30425==    by 0x804BE2E: rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>::~MemoryPoolAllocator() (allocators.h:140)

==30425==    by 0x804BE5F: rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>::Destroy() (document.h:2382)

==30425==    by 0x804BE7E: rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>::~GenericDocument() (document.h:2064)

#include <rapidjson/schema.h>

#include <rapidjson/document.h>

#include <rapidjson/stringbuffer.h>

#include <rapidjson/writer.h>

#include <string>

#include <vector>

int main()

std::vector<rapidjson::Document*> subs;

rapidjson::Document doc;

doc.Parse("{}");

// 注意,下面没有使用Document的默认构造,

// 而是指定Allocator为其父的Allocator。

// 如果存在多级Document,一定要统一使用根Document的Allocator,

// 原因是Allocator分配的内存会随Document析构被释放掉!

// 如果不这样做,必须保证sub的生命在doc之后才结束。

rapidjson::Document sub(&doc.GetAllocator());

sub.Parse("{\"name\":\"tom\"}");

doc.AddMember("sub", sub, doc.GetAllocator());

rapidjson::StringBuffer buffer;

rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

doc.Accept(writer);

printf("%s\n", buffer.GetString());

for (std::vector<rapidjson::Document*>::size_type i=0; i<subs.size(); ++i)

rapidjson::Document *sub_ptr = subs[i];

delete sub_ptr;

subs.clear();

return 0;