message MyProto { optional bytes data = 1; }
我不能控制的API给我一个指向源数据及其大小的指针.我想让一个MyProto从这个数据中没有深入的复制.我以为这很容易做,但似乎是不可能的. set_data很容易深入复制. Protobuf提供了一个set_allocated_data函数,但是它需要一个指向std :: string的指针,它不能帮助我,因为(除非我被误认为)没有办法使std :: string没有深入复制.
void populateProto(void* data,size_t size,MyProto* message) { // Deep copy is fine,I guess. message->set_data(data,size); // Shallow copy would be better... // message->set_allocated_data( ??? ); }
有没有办法正确地填充这个proto(这样可以稍后序列化),而不会将源数据深入复制到字节字段中?
我知道我可以立即手动进行序列化,但如果可能的话我宁愿不做.
解决方法
>如果您可以更改.proto文件,请考虑实施StringPiece
的ctype字段选项,Google相当于即将发布的C 17 string_view
.这就是Google在内部处理这种情况. FieldOptions消息已经有semantics for StringPiece,但Google还没有开源实施.
message MyProto { bytes data = 1 [ctype = STRING_PIECE]; }
有关实施指南,请参见this discussion.您可以忽略竞技场分配的注释,这不适用于您的情况.值得Google询问ETA.
>使用不同的协议缓冲区实现,也许只针对这种特定的消息类型. protobuf-c和protobluff是看起来很有前途的C语言实现.
>向第三方API提供缓冲区.我从评论中看到,你不能,但我把它包括在内.
::str::string* buf = myProto->mutable_data(); buf->reserve(size); api(buf->data(),size); // data is contiguous per c++11 std
> NON STANDARD:通过覆盖字符串实例中的数据来打破封装. C有一些精彩的功能,给你足够的绳子来挂自己.这个选项不安全,取决于你的std :: string的执行和其他因素.
// NEVER USE THIS IN PRODUCTION void string_jam(::std::string * target,void * buffer,size_t len) { /* On my system,std::string layout * 0: size_t capacity * 8: size_t size * 16: char * data (iff strlen > 22 chars) */ assert(target->size() > 22); size_t * size_ptr = (size_t*)target; size_ptr[0] = len; // Overwrite capacity size_ptr[1] = len; // Overwrite length char ** buf_ptr = (char**)(size_ptr + 2); free(*buf_ptr); // Free the existing buffer *buf_ptr = (char*)buffer; // Jam in our new buffer }
注意:这可能会让你被解雇.这对于测试性能影响是有用的,如果你做了零拷贝路由,但不要在prod中.
如果你选择#1,那么如果你可以释放源代码,那么很多人会受益于这个能力.最好的运气.