假设我有一个带字节字段的proto:
#include <iostream>
#include <string>
using namespace std;
void readDate (char array[]);
void GetDate (char array[]);
const int size = 11;
int main ()
{
char original[size];
readDate(original); // call readDate
GetDate(original); // call GetDate
return 0;
}
void readDate (char array[])
{
string month;
cout << "Enter a date (Ex: Jan/20/2003): ";
cin.getline (array, size); // read size characters into the character array
cin >> month;
}
void getDate (char array[])
{ string month;
string Jan, Feb, Mar, Apr, May, Jun, July, Aug, Sept, Oct, Nov, Dec;
cout << "Date in converted format is: ";
if (month == Jan) {
cout << "01";
}
else if (month == Feb) {
cout << "02";
}
else if (month == Mar) {
cout << "03";
}
else if (month == Apr) {
cout << "04";
}
else if (month == May) {
cout << "05";
}
else if (month == Jun) {
cout << "05";
}
else if (month == July) {
cout << "07";
}
else if (month == Aug) {
cout << "08";
}
else if (month == Sept) {
cout << "09";
}
else if (month == Oct) {
cout << "10";
}
else if (month == Nov) {
cout << "11";
}
else if (month == Dec) {
cout << "12";
}
cout << array[3] << array[4] << array[6] << array[7] << array[8] << array[9] << endl;
}
我无法控制的API为我提供了指向源数据及其大小的指针。我希望在没有深度复制的情况下从这些数据中创建一个message MyProto {
optional bytes data = 1;
}
。我认为这很容易做到,但似乎不可能。 MyProto
可以轻松进行深度复制。 Protobuf提供了一个set_data
函数,但它需要一个指向set_allocated_data
的指针,这对我没有帮助,因为(除非我弄错了)没有办法让std::string
没有深深地抄袭它。
std::string
有没有办法正确填充这个原型(以便以后可以序列化)而无需将源数据深度复制到字节字段中?
我知道我可以立即手动进行序列化,但如果可能的话,我宁愿不这样做。
答案 0 :(得分:5)
好问题。选项包括:
如果您可以更改.proto文件,请考虑为StringPiece
实施ctype
字段选项,Google等同于即将推出的C ++ 17 string_view
。这就是谷歌在内部处理这种情况的方式。 FieldOptions
消息已有semantics for StringPiece,但Google尚未开源实施。
message MyProto {
bytes data = 1 [ctype = STRING_PIECE];
}
有关实施指南,请参阅this discussion。您可以忽略竞技场分配的注释,这不适用于您的情况。值得向谷歌询问ETA。
使用不同的协议缓冲区实现,可能仅适用于此特定消息类型。 protobuf-c和protobluff是看起来很有前途的C语言实现。
将缓冲区提供给第三方API。我从评论中看出你不能,但我把它包括在内是为了完整。
::str::string* buf = myProto->mutable_data();
buf->resize(size);
api(buf->data(), size); // data is contiguous per c++11 std
非标准:通过覆盖字符串实例中的数据来中断封装。 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选项,那么如果您可以发布源代码就会很棒,因为许多其他人都会从这个功能中受益。祝你好运。