3

我似乎无法在 protobuf中找到MessageLiteMergeFrom*类的方法和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_ptrforpayloadBuf就像我为prefixBuf.

感谢您的输入!

4

2 回答 2

6

首先MergeFrom*不要像ParseFrom*方法一样工作。第一个像MergeFromMessage 类一样工作:

单个字段将被覆盖,除了将被合并的嵌入消息。重复的字段将被连接。

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

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

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

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

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

于 2012-10-16T22:27:21.717 回答
2

检查ArrayInputStream的文档:

“数据”仍然是调用者的属性,但在流被销毁之前必须保持有效。

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

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

于 2012-10-16T22:19:13.283 回答