Protobuf c++使用小坑(set_allocated函数)

protobuf是后台开发中,比较常用的数据通信协议。相对于json,具有数据压缩率高等优点。但是,在某些情况下,稍不留神容易用错。


最近使用protobuf的时候,使用了相对陌生的复合类型的赋值。结果用错了,然后就莫名其妙core dump了。

使用的数据类型简化如下:

message Answer 
{
    optional uint32 choice = 1;
    optional uint32 id = 2;
}

message Detail
{
    optional Answer answer = 1;
    optional uint32 id  = 2;
}

message Rsp
{
    repeated Detail detail = 1;
}


message Info
{
    repeated Answer answer = 1
}


大概的使用过程是这样的:需要在一个for循环里面,把一个Class中的每一个student拷贝到一个局部的Family对象中的owner中。查看了protoc生成的pb.h文件之后,发现有一个set_allocated_owner(::Person* person)这样的函数。所以,我就使用了如下的代码:

//info 是一个已经定义好的Info对象
Rsp rsp;
for(int index = 0;index



然后就coredump了,用gdb调试的时候,发现一堆和protobuf相关的东西,猜测应该是protobuf用错了,但是想了很久都没有想到是什么。

但是凭借直觉,这种coredump一般都是和指针相关,想到也就这个地方用了指针,就果断google了一发protobuf的set_allocated相关的函数,发现果然是用错了。


看到了这篇文章:http://blog.csdn.net/xiaxiazls/article/details/50118161


主要的意思就是,那个temp_ans是局部变量,会在for循环中一个循环结束之后被析构的,然而,set_allocated_answer中放进去的是这个局部变量的指针。所以,后面这个rsp使用的时候,里面的detail的answer的指针已经指向了非法的内存空间了。coredump妥妥的。


如果需要使用set_allocated这种方法,参数里面的指针需要指向一个在使用到这个数据的时候还没有被析构的对象(好绕口)。例如,那个指针参数是new 出来的,或者是在一个更外层的嵌套中定义的。但是,protobuf中会负责析构这个传进去的指针指向的对象,所以,最好传进去一个new出来的对象的地址,因为如果传进去一个原来就定义好的对象的地址,可能因为这个析构,而导致原有对象失效,造成一些潜在的问题(set_allocated_xxx中的allocated已经表明,最好是那种分配出来的对象)


像上面的例子,进行复合类型的赋值,用copyFrom比较好,例子如下:

Rsp rsp;
for(int index = 0;indexmutable_answer();
    Answer temp_ans = info.answer(index);
    ans->copyFrom(temp_ans);
}
//do something with rsp




你可能感兴趣的:(学习笔记)