Google的protobuf库中的MergeFrom* vs. ParseFrom*

MergeFrom* vs. ParseFrom* in Google's protobuf library

本文关键字:vs ParseFrom MergeFrom protobuf Google      更新时间:2023-10-16

我似乎找不到protobuf中MessageLite类的MergeFrom*ParseFrom*方法之间的明显区别。

我正在尝试尽量减少我必须执行的数据复制量,因此我在下面编写了以下代码来解码以长度为前缀的消息:

bool StreamMessageDelimiter::receiveWithLengthPrefix(Message& message)
{
google::protobuf::uint32 messageSize;
auto_ptr<google::protobuf::uint8> prefixBuf(new google::protobuf::uint8[sizeof(messageSize)]);
int receivedBytes = receiveNBytes(prefixBuf.get(), sizeof(messageSize));
if(receivedBytes != sizeof(messageSize))
{
return false;
}
CodedInputStream prefixInput(prefixBuf.get(), sizeof(messageSize));
prefixInput.ReadLittleEndian32(&messageSize);
google::protobuf::uint8* payloadBuf = new google::protobuf::uint8[messageSize];
receivedBytes = receiveNBytes(payloadBuf, messageSize);
if(receivedBytes != messageSize)
{
return false;
}
ArrayInputStream rawInput(payloadBuf, messageSize);
CodedInputStream codedInput(&rawInput);
if(!message.MergeFromCodedStream(&codedInput))
{
return false;
}
return true;
}

我的问题是使用MergeFromCodedStream会导致message获得payloadBuf的所有权,还是message制作基础数据的副本?如果message确实复制了,那么我显然应该像prefixBuf一样使用auto_ptrpayloadBuf

感谢您的输入!

首先MergeFrom*不像ParseFrom*方法那样工作。 第一个工作原理类似于 Message 类中的MergeFrom

单数字段将被覆盖,但将被合并的嵌入式消息除外。重复的字段将被连接起来。

ParseFrom是一个包装器,只需在调用MergeFrom之前调用Clear

Clear() 避免释放内存,假设分配用于保存部分消息的任何内存都需要再次用于保存下一条消息。如果您确实要释放消息使用的内存,则必须将其删除。

因此,在您的消息被清除之前,所有重复的字段都将聚合新数据。

存储在序列化流中的数据是 Varint 编码的,因此解析是通过解释流中的数据并复制到 Message 对象字段中来完成的。

解析完成后,消息本身将不需要缓冲区。

查看 ArrayInputStream 的文档:

"数据"仍然是调用方的属性,但必须保持有效,直到 流被销毁。

所以不,它不拥有所有权,您应该确保在正确的时间释放内存。

我想您可能会对函数名称中使用单词Merge感到困惑。它不是说"数据从传递的缓冲区合并"(我认为这导致您考虑所有权),而是"数据合并到消息中"。因此,Parse在填充消息之前调用Clear(),而Merge则按原样直接使用您传递的消息。