Я пытаюсь работать с rapidjson.
Я хочу сгенерировать строку и добавить ее к некоторому объекту rapidjson::Value
.
Я использовал std::string при работе с qjson, но в случае rapidjson это кажется неуместным. Я не хочу генерировать строку, а затем копировать ее, время жизни строкового объекта заканчивается до времени жизни объекта (rapidjson::Value
) (поэтому generated_string.c_str()
не является случаем). В json может быть \0, поэтому char*
со строкой, заканчивающейся нулем, также не является решением.
Итак, я должен написать свой собственный строковый тип? Или используйте что-то вроде
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);
// ...
}
Или есть какие-то другие способы работы со строками? Мне кажется тяжело. Мы не можем переместить строку в rapidjson::Value
из-за различных структур внутри этого Value
, мы не можем установить указатель внутри Value
в c_str()
, потому что строка будет уничтожена до Value
. Даже с GenericStringRef<char>
приходится переписывать почти всю работу со строками.
Кстати, почему RAPIDJSON_HAS_STDSTRING
по умолчанию 0? Какие-то проблемы с работой? Я вижу, что могу скопировать строку в rapidjson::Value
и скопировать указатель, если я знаю, что время жизни строки закончится до времени жизни значения.
UPD: Теперь я вижу, что rapidjson освобождает только те строки, которые были скопированы:
//! 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.
}
}
}
Итак, как было сказано в ответе, использовать GenericStringRef
таким образом, как в моем коде здесь, - плохая идея, потому что в таком случае я должен сам управлять памятью.