有没有一种有效的方法将 rapidjson 与 std::string 结合使用?

10

我正在尝试使用 rapidjson。

我想生成字符串并将其添加到某个rapidjson :: Value对象中。

在使用qjson时,我使用了std :: string,但是在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中并复制指针。

更新:现在我知道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这种方式是一个坏主意,因为在这种情况下,我必须自己管理内存。
1个回答

12

我不完全理解这个问题。但是我在这里尝试澄清一些事情。

  1. GenericStringRef 用于防止字符串复制。只有在字符串的生命周期足够长的情况下才应使用它。对于动态创建的字符串,通常不应使用 GenericStringRef
  2. 设置 RAPIDJSON_HAS_STDSTRING=1 是可以的。它默认未开启,因为其支持是在早期版本之后添加的。如果用户不需要,我不希望 RapidJSON 头文件包含 <string>。由于您使用了 std::string,您可以将其打开。它应该会让您更容易处理 std::string

1
抱歉,经过一段时间的思考,我意识到这是个糟糕的问题:如果我想始终使用std::string(和rapidjson),在某些情况下我必须复制字符串,如果我想避免复制,我必须使用char*或者从rapidjson中选择一些类型,就像在问题中提到的那样。 - ckorzhik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接