I'm trying to work with rapidjson.
I want to generate string and add it to some rapidjson::Value
which is object.
I was using std::string when worked with qjson, but in case of rapidjson it seems inappropriate. I don't want to generate string and then copy it, string object lifetime ends before object (rapidjson::Value
) lifetime (therefore generated_string.c_str()
is not a case).
There may be \0 in json, so, char*
with null-terminated string also not a solution.
So, I must write my own string type? Or use something like
auto create_string_object() -> rapidjson::GenericStringRef<char>
{
size_t len;
char* result;
// generate char* result with length len
const char* return_value = result;
return rapidjson::StringRef(return_value,len);
}
auto create_object_object(rapidjson::Document::AllocatorType &allocator) -> rapidjson::Value
{
// ...
rapidjson::Value result(rapidjson::kObjectType);
rapidjson::Value tmp; // tmp = create_string_object() will not compile
tmp = create_string_object();
result.AddMember("key", tmp, allocator);
// ...
}
Or there are some other ways to work with strings? It seems hard to me. We can't move string to rapidjson::Value
because of different structures inside that Value
, we can't set pointer inside Value
to c_str()
because string will be destroyed before Value
.
Even with GenericStringRef<char>
I must rewrite almost all work with strings.
By the way, why RAPIDJSON_HAS_STDSTRING
is 0 by default? Some problems with work? I see that i can copy string into rapidjson::Value
and copy pointer if I know that string lifetime will end before value lifetime.
UPD: Now I see that rapidjson frees only strings that were copied:
//! Destructor.
/*! Need to destruct elements of array, members of object, or copy-string.
*/
~GenericValue() {
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
switch(flags_) {
case kArrayFlag:
for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
v->~GenericValue();
Allocator::Free(data_.a.elements);
break;
case kObjectFlag:
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
m->~Member();
Allocator::Free(data_.o.members);
break;
case kCopyStringFlag:
Allocator::Free(const_cast<Ch*>(data_.s.str));
break;
default:
break; // Do nothing for other types.
}
}
}
So, as it was said in answer, using GenericStringRef
in a way such as in my code here is a bad idea, because in such case I must manage memory by myself.