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,那么如果你可以释放源代码,那么很多人会受益于这个能力.最好的运气.