将数据序列化为 std::vector<uint8_t> - Protobuf C++

Serialize data to std::vector<uint8_t> - Protobuf C++

我被困在一个简单但痛苦的任务中:用 C++ 进行数据解析。我需要将 Protobuf 对象的数据内容序列化为 std::vector<uint8_t>。我见过几个使用 SerializeToArray 方法将数据序列化到 *voidchar[] 缓冲区的示例,但不是我需要的。我想参与其中,感谢您的支持。

注意:我需要 std::vector<uint8_t>,而不是 std::vector<uint8_t>& 或其他人。

如果你需要使用 std::vector 你可以这样做(从我的头顶):

#include <vector>
#include <cstdint>

// Adjust this value to match your maximum message size.
constexpr MAX_N_BYTES = 100;

// Allocate enough space for your message in the vector.
std::vector<uint8_t> vec;
vec.reserve(MAX_N_BYTES);

// The allocation of your message.
YourMessage msg;

// Set some data
msg.set_x(1234);

// Next serialize to the data into the vector.
msg.SerializeToArray(vec.data(), vec.max_size());

但是我不建议您使用这样的 std::vector。 vector 容器真正设计用于在底层管理内存的顶层。

我认为更合适的容器是 std::array。这是一个更类似于普通 C 样式数组的容器。其实现如下所示:

#include <array>
#include <cstdint>

// Adjust this value to match your maximum message size.
constexpr MAX_N_BYTES = 100;

// Allocate the array
std::array<uint8_t, MAX_N_BYTES> array;

// The allocation of your message.
YourMessage msg;

// Set some data
msg.set_x(1234);

// Next serialize to the data into the array.
msg.SerializeToArray(array.data(), MAX_N_BYTES);

请注意,在这两种情况下,您确实需要提前知道消息的最大大小。这是为了分配适当数量的内存。

直接的解决方案是将 std::vector<uint8_t> 预设置为正确的大小:

  size_t nbytes = std::vector<uint8_t> v(proto_object.ByteSizeLong());
  /* The test is necessary becaue v.data could be NULL if nbytes is 0 */
  if (nbytes)
    proto_object.SerializeToArray(v.data(), nbytes);

这里唯一的问题是 v 的内容在被 SerializeToArray 覆盖之前被构造函数设置为 0。那不是错误;该代码可以正常工作。但效率低下。

能够创建未初始化值的向量是一个长期存在的讨论点。有很多方法可以做到这一点,但简单的方法需要使用与 std::vector<uint8_t> 略有不同的类型:一种可能性是使用带有自定义分配器的向量;另一种是使用基于 uint8_t 的非初始化数据类型。这两个都很烦人,因为你不能在不复制的情况下更改 vector 的分配器或值类型,这违背了目的。

所以最简单的事情就是接受低效率,这可能并不那么严重,因为将序列化数据发送到任何地方的成本可能会使不必要的初始化相形见绌。无论如何,清除内存肯定比从临时缓冲区复制便宜,而且不需要创建临时缓冲区。