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;