Есть ли способ эффективно использовать rapidjson с std::string?

Я пытаюсь работать с 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 таким образом, как в моем коде здесь, - плохая идея, потому что в таком случае я должен сам управлять памятью.


person ckorzhik    schedule 10.05.2015    source источник


Ответы (1)


Я не совсем понимаю вопрос. Но здесь я попытаюсь прояснить некоторые вещи.

  1. GenericStringRef используется для предотвращения копирования строки. Его следует использовать только в том случае, если известно, что время жизни строки достаточно. Для динамически созданной строки обычно не следует использовать GenericStringRef.
  2. Настройка RAPIDJSON_HAS_STDSTRING=1 в порядке. Он не включен по умолчанию, потому что его поддержка добавлена ​​после раннего выпуска. И я не хочу, чтобы заголовок RapidJSON включал <string>, если пользователю это не нужно. Поскольку вы используете std::string, вы можете включить его. Вам должно быть легче иметь дело с std::string.
person Milo Yip    schedule 11.05.2015
comment
Спасибо. Извините, после некоторого размышления я понял, что это плохой вопрос: если я хочу всегда работать с std::stringrapidjson), я должен в некоторых случаях копировать строки, если я хочу избежать копирования, я должен использовать char* или некоторые типы из rapidjson, как в вопросе. - person ckorzhik; 11.05.2015