我似乎无法明确区分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
确实复制了,那么我显然应该使用auto_ptr
payloadBuf
,就像我为prefixBuf
所做的那样。
感谢您的投入!
答案 0 :(得分:5)
首先MergeFrom*
不像ParseFrom*
方法那样工作。
第一个像Message class中的MergeFrom
一样工作:
除了将要合并的嵌入消息之外,将覆盖奇异字段。重复的字段将被连接。
ParseFrom
是一个包装,只需在致电Clear
之前致电MergeFrom
:
Clear()避免释放内存,假设将再次需要分配用于保存部分消息的任何内存来保存下一条消息。如果您确实要释放消息使用的内存,则必须将其删除。
因此,在您的消息被清除之前,所有重复的字段都会聚集新数据。
存储在序列化流中的数据是Varint encoded,因此解析是通过解释流中的数据并复制到Message对象字段来完成的。
解析完成后,消息本身不需要缓冲区。
答案 1 :(得分:1)
查看ArrayInputStream的文档:
“data”仍然是调用者的属性,但必须保持有效直到 溪流被毁坏了。
所以不,它不占用所有权,你应该确保在合适的时间释放内存。
我认为您可能会对函数名称中使用单词Merge
感到困惑。它并没有说“数据从传递的缓冲区合并”(我认为这会让你考虑所有权),而是“数据被合并到消息中”。因此,Parse
在填写邮件之前调用Clear()
,而Merge
使用您按原样直接传递的邮件。