(2)protobuf不支持二维数组(指针),不支持STL容器序列化

这个缺陷挺大,因为稍复杂点的数据结构或类结构里出现二维数组、二维指针和STL容器(set、list、map等)很频繁,但因为 protobuf简单的实现机制,只支持一维数组和指针(用repeated修饰符修饰),不能使用repeated repeated来支持二维数组, 也不支持STL,因此在选择该方案之前,一定 要确保你的数据结构里没有这些不支持的类型。

(3)protobuf嵌套后会改变类名称

protobuf支持类的嵌套,即在一个自定义类型中可以定义另一个自定义类型,但注意嵌套的自定义类型在经过protobuf处理后生成的类名称并不是你定义的类名称,而是加上了外层的类名称作为前缀,下面举一个简单的例子:

message DFA {

required int32 _size =1;


message accept_pair {

required boolis_accept_state =1;

required boolis_strict_end =2;

optional stringapp_name =3;

}


repeated accept_pair accept_states =2;

}


那么嵌套中的accept_pair 生成后的类不是accept_pair 而是DFA_accept_pair 。如果不想改类名称,将accept_pair 拿到外面与DFA平行定义即可。

4.2 Boost.Serialization

Boost库是个很庞大的库,功能非常丰富,序列化只是其中的一个小分支,但为了使用Boost的序列化方案,你需要安装整个Boost库,所花费的磁盘空间和时间都很多,同样支持的序列化功能也很强大,既支持二维数组(指针),也支持STL容器,更不需要我们用某种特殊的格式重新定义我们的类结构,其非侵入的性质使得我们无须改动已有的类结构即可序列化,这时非常赞的一个性质。但是由于体积庞大,安装复杂,如果只是简单的序列化,没必要使用该方案,只有protobuf不能满足你的需求时,才应该考虑该方案。

(1)安装boost库遇到的一系列问题

安装boost库本事就是一项很费时的工程,如果期间出现了各种错误,更加耗时耗耐心。我们可以从 官网下载 Boost库的二进制源码进行安装,安装方法可以参考网络或后面我给出的参考资料。

安装过程如下:

首先解压安装包,如果是tar.gz用tar zxvf解压,如果是tar.bz2用tar jxvf解压,解压后进入解压后的目录,依次运行以下命令:

./bootstrap.sh

sudo ./b2 install

注:这里没有指定安装路径,在第二个命令可以加入--prefix指定安装目录。


安装时的注意事项:

注意1:要用root权限进行安装,否则会在安装过程中报错,提示权限不足。

注意2:boost库的安装依赖一些环境,通常有Python、bzip2和zlib,它们所在的软件包分别为:

Ubuntu下:

zlib1g-dev

libbz2-dev

libpython2.7-dev (and libpython3.3-dev)


Fedora/Redhat下:

zlib-devel

libbz2-devel

python-devel (and python3-devel)

这也是安装过程中报错的主要来源。

报错1:如果Python库不完整,可能会报“ fatal error: pyconfig.h: No such file or directory compilation terminated.”或者“fatal error: patchlevel.h: No such file or directory”错误。解决方法如下:

Fedora系统:sudo yum install python-devel

Ubuntu系统:sudo apt-get  install python-dev

报错2:报错 “ libs/iostreams/src/bzip2.cpp:20:56: fatal error: bzlib.h: No such file or directory”,解决方案:

Fedora系统:sudo yum install bzip2-devel

Ubuntu系统或Debian系统:sudo apt-get install libbz2-dev

通常对于这些错误,在Ubuntu系统下一般可以通过sudo apt-get install libboost-all-dev全部解决,但不一定行得通。

(2)安装成功后,如果未指定安装位置,那么默认将会安装到/usr/local/lib和/usr/local/include下,那么我们在使用Boost库进行编译时就需要使用-L和-I参数加上具体的lib和include路径 ,像下面这样:

g++ -o test boost_test.cpp -I$BOOST_INCLUDE -L$BOOST_LIB -lboost_serialization

如果觉得每次都这样很麻烦,那么可以将我们所要用到的lib和include文件加入到环境变量中,像下面这样:

sudo cp /usr/local/lib/libboost_serialization.* /usr/lib

sudo cp -r /usr/local/include/boost /usr/include

然后在编译时直接g++ -o test boost_test.cpp -lboost_serialization即可。

注意:boost下面有两个序列化lib文件:ibboost_serialization.lib 和 libboost_wserialization.lib,那么这两者有什么区别呢?

其实'w' 表示使用的是宽字符,例如 wchar_t。

(3)boost不尽人意的地方

基本类型指针很难序列化,例如int *array, 官网 上是这么说的:

By default, data types designated primitive by Implementation Level class serialization trait are never tracked. If it is desired totrack a shared primitive object through a pointer (e.g. along used as a reference count), It should be wrappedin a class/struct so that it is an identifiable type.The alternative of changing the implementation level of alongwould affect alllongs serialized in the wholeprogram - probably not what one would intend.

也就是说如果你想序列化原生类型的指针,需要给其加上struct或class使其变为类类型再序列化,可见有些麻烦,这样的需求往往也很频繁,鉴于序列化机制的实现原理,boost库暂时还不能很好的支持基本类型的指针序列化。

不能序列化变长数组(variable-sized array),会报错说变长数组不是模板类类型。

(4)如果需要定义一个对象数组,如定义含有2个元素的class A对象数组,那么必须用A a[2]定义而不能用对象的指针A *a = new A[2]定义,这样序列化a后默认当作一个A对象处理,因此只能存储一个对象的值,后面的不会存储。

(5)所谓boost很人性的非侵入性质也有一定的条件:如果不想改动原来的类,那么原来的类属性必须是public的,这很容易解释,因为你必须 要能在别处访问到这些属性并定义其序列化方式,当然这也在其它地方暴露了类的结构,具有一定的劣势。这样的条件往往很难满足,因为我们定义的类属性一般都 是private的,如果是这样,且仍想要使用非侵入性质,那么需要在类中添加以下声明来开放访问给 serialization 库:

friend class boost::serialization::access;

这样的方式比让成员public更好。

文末也给大家,分享主要有C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK技术,面试技巧方面的资料技术讨论。

感兴趣的朋友可以加群:812855908