如何将 std::string 反序列化为 Cap'n Proto C++ 中的具体消息?

How to deserialize a std::string to a concrete message in Cap'n Proto C++?

我需要解码来自 std::string 对象的消息。

我知道如何做到这一点 in Java by using a ByteBuffer,但我找不到简单的 C++ 等价物。

更准确地说,如何实现?

const std::string serialized_data = ...; // Source
SomeDataType data = ???; // How to convert from serialized_data to data?

你可以这样写代码:

std::string serialized_data = ...;
kj::ArrayPtr<const capnp::word> words(
    reinterpret_cast<const capnp::word*>(serialized_data.begin()),
    serialized_data.size() / sizeof(capnp::word));
capnp::FlatAraryMessageReader reader(words);

请注意,这假设 std::string 的后备缓冲区始终是 word-aligned。我认为这是真的,但我不确定。如果它没有对齐,你会得到异常说明。在这种情况下,可能需要将数据复制到对齐的缓冲区中:

auto words = kj::heapArray<capnp::word>(
    serialized_data.size() / sizeof(capnp::word));
memcpy(words.begin(), serialized_data.begin(), words.asBytes().size());
capnp::FlatAraryMessageReader reader(words);

请注意,虽然 std::string 在技术上能够存储任意字节,但它并不是用于此目的的特别好的数据结构,因为它针对文本进行了优化。例如,它可能 re-allocate 并复制您的缓冲区以添加 NUL 终止符以支持 .c_str()。我建议对字节数组使用更多 data-oriented 类型。

我自己的回答与 Kenton 的非常相似:

std::string serialized_data = ...;
kj::ArrayPtr<const kj::byte> arr(
  reinterpret_cast<const kj::byte*>(serialized_data.data()),
  serialized_data.size());
kj::ArrayInputStream stream(arr);
capnp::InputStreamMessageReader reader(stream);
auto data = reader.getRoot<SomeDataType>();

这与 Java 版本同构,并且没有对齐要求。

但 Kenton 的解决方案比这更直接。因此我会进一步简化我的程序。