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.
I do not completely understand the question. But I try to clarify a few things here.
GenericStringRef
is used for preventing string copy. It should only be used if the string's lifetime is known to be sufficient. For string dynamically created, normally you should not use GenericStringRef
.RAPIDJSON_HAS_STDSTRING=1
is fine. It is not turned on by default because its support is added after early release. And I don't want RapidJSON header to include <string>
if the user don't need to. Since you use std::string
, you can turn it on. It should make you easier to deal with std::string
.