损坏的输出,可能是由于 rapidjson::Document::Allocator 的所有权丢失
Corrupt output, possibly due to lost ownership of rapidjson::Document::Allocator
我认为对象所有权有一些问题。我的目标是创建一个 JSON-RPC 消息。我想在较低层次上实现的是一个对象数组,每个对象都有1个对象error
。一切顺利,除了内部 error
对象。
您可以在下面找到我的代码的输出。如您所见,error.message
的前 8 个字符已替换为 null
个字符。预期输出应为 Internal error: Don't know what happened
.
[{"error":{"code":-32603,"message":"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000 error: Don't know what happened"},"jsonrpc":"2.0","id":null}]
由于每个对象都是在循环内创建并添加到数组中的,因此每次迭代后范围都会丢失,所以我认为它与所有权有关。可能 something like this?我尝试了所有我能想到的方法:为循环内的 error
对象创建 Document
和 AllocatorType
,复制而不是移动构造所有对象,等等,但我是有点卡在这里。谁能帮我管理内部 error
对象的所有权?
提前致谢!
我的代码:
void MessageCenter::write_rpc_response(network::Session& session,
const std::vector<RPCResponse>& rpc_responses)
{
rapidjson::Document json_responses;
rapidjson::Document::AllocatorType& alloc = json_responses.GetAllocator();
json_responses.SetArray();
std::vector<RPCResponse>::const_iterator iter;
for (iter = rpc_responses.begin(); iter != rpc_responses.end(); iter++)
{
rapidjson::Document resp;
resp.SetObject();
// Create error object, based on std::map
struct { int64_t code = 0; std::string message = ""; } error;
error.code = -32603;
error.message = "Internal error: Don't know what happened";
// Create JSON object, based on the error object
rapidjson::Value data_object(rapidjson::kObjectType);
data_object.AddMember("code",
rapidjson::Value(error.code).Move(), alloc);
rapidjson::Value error_message(error.message.c_str(),
error.message.length());
data_object.AddMember("message", error_message.Move(), alloc);
resp.AddMember("error", data_object.Move(), alloc);
// Add JSON-RPC version
rapidjson::Value jsonrpc_version(iter->jsonrpc.c_str(),
iter->jsonrpc.length());
resp.AddMember("jsonrpc", jsonrpc_version.Move(), alloc);
// Add id: null if 0, int otherwise
if (iter->id == 0) {
resp.AddMember("id", rapidjson::Value().Move(), alloc);
}
else {
resp.AddMember("id", rapidjson::Value(iter->id).Move(), alloc);
}
json_responses.PushBack(resp, alloc);
}
// Write to the session
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
json_responses.Accept(writer);
session.Write(buffer.GetString());
}
构造字符串有几个API:
//! Constructor for constant string (i.e. do not make a copy of string)
GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
//! Constructor for constant string (i.e. do not make a copy of string)
explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); }
//! Constructor for copy-string (i.e. do make a copy of string)
GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); }
//! Constructor for copy-string (i.e. do make a copy of string)
GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
以下代码使用常量字符串版本:
rapidjson::Value error_message(error.message.c_str(),
error.message.length());
但显然 error
将超出范围。您应该使用复制字符串 API:
rapidjson::Value error_message(error.message.c_str(),
error.message.length(), alloc);
顺便说一下,resp
不需要是 Document
。它可以只是一个 Value
。不过,如果您始终使用外部分配器,这不会产生错误。
我认为对象所有权有一些问题。我的目标是创建一个 JSON-RPC 消息。我想在较低层次上实现的是一个对象数组,每个对象都有1个对象error
。一切顺利,除了内部 error
对象。
您可以在下面找到我的代码的输出。如您所见,error.message
的前 8 个字符已替换为 null
个字符。预期输出应为 Internal error: Don't know what happened
.
[{"error":{"code":-32603,"message":"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000 error: Don't know what happened"},"jsonrpc":"2.0","id":null}]
由于每个对象都是在循环内创建并添加到数组中的,因此每次迭代后范围都会丢失,所以我认为它与所有权有关。可能 something like this?我尝试了所有我能想到的方法:为循环内的 error
对象创建 Document
和 AllocatorType
,复制而不是移动构造所有对象,等等,但我是有点卡在这里。谁能帮我管理内部 error
对象的所有权?
提前致谢!
我的代码:
void MessageCenter::write_rpc_response(network::Session& session,
const std::vector<RPCResponse>& rpc_responses)
{
rapidjson::Document json_responses;
rapidjson::Document::AllocatorType& alloc = json_responses.GetAllocator();
json_responses.SetArray();
std::vector<RPCResponse>::const_iterator iter;
for (iter = rpc_responses.begin(); iter != rpc_responses.end(); iter++)
{
rapidjson::Document resp;
resp.SetObject();
// Create error object, based on std::map
struct { int64_t code = 0; std::string message = ""; } error;
error.code = -32603;
error.message = "Internal error: Don't know what happened";
// Create JSON object, based on the error object
rapidjson::Value data_object(rapidjson::kObjectType);
data_object.AddMember("code",
rapidjson::Value(error.code).Move(), alloc);
rapidjson::Value error_message(error.message.c_str(),
error.message.length());
data_object.AddMember("message", error_message.Move(), alloc);
resp.AddMember("error", data_object.Move(), alloc);
// Add JSON-RPC version
rapidjson::Value jsonrpc_version(iter->jsonrpc.c_str(),
iter->jsonrpc.length());
resp.AddMember("jsonrpc", jsonrpc_version.Move(), alloc);
// Add id: null if 0, int otherwise
if (iter->id == 0) {
resp.AddMember("id", rapidjson::Value().Move(), alloc);
}
else {
resp.AddMember("id", rapidjson::Value(iter->id).Move(), alloc);
}
json_responses.PushBack(resp, alloc);
}
// Write to the session
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
json_responses.Accept(writer);
session.Write(buffer.GetString());
}
构造字符串有几个API:
//! Constructor for constant string (i.e. do not make a copy of string)
GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
//! Constructor for constant string (i.e. do not make a copy of string)
explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); }
//! Constructor for copy-string (i.e. do make a copy of string)
GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); }
//! Constructor for copy-string (i.e. do make a copy of string)
GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
以下代码使用常量字符串版本:
rapidjson::Value error_message(error.message.c_str(),
error.message.length());
但显然 error
将超出范围。您应该使用复制字符串 API:
rapidjson::Value error_message(error.message.c_str(),
error.message.length(), alloc);
顺便说一下,resp
不需要是 Document
。它可以只是一个 Value
。不过,如果您始终使用外部分配器,这不会产生错误。