boost程序库探秘库序列化

下次自动登录
现在的位置:
& 综合 & 正文
C++ 中基础中boost的序列化的例子
#include "obj.hpp"
#include &assert.h&
#include &fstream&
#include &boost/archive/text_iarchive.hpp&
#include &boost/archive/text_oarchive.hpp&
int main(void)
char *filename = "save.txt";
const obj o1(-2, false);
const obj o2;
const obj o3(21, true);
const obj *const p1 = &o1;
//save the obj data
{&br&        //打开save.txt&br&         std::ofstream ofs(filename);
boost::archive::text_oarchive ar(ofs);
        //将o1 o2 o3 p1 的数据记录到
ar & o1 & o2 & o3 & p1;
obj restored_o1;
obj restored_o2;
obj restored_o3;
obj *restored_p1;
std::ifstream ifs(filename);
boost::archive::text_iarchive iar(ifs);
iar & restored_o1 & restored_o2 & restored_o3 &
restored_p1;
assert(restored_o1 == o1);
assert(restored_o2 == o2);
assert(restored_o3 == o3);
assert(restored_p1 != p1);
assert(restored_p1 == &restored_o1);
#pragma once
namespace boost {
namespace serialization {
class obj {
obj():d1_(-1),d2_(false){}
obj(int d1,int d2):d1_(d1),d2_(d2){}
bool operator==(const obj &o) const {
return d1_ == o.d1_ && d2_ == o.d2_;
friend class boost::serialization::
template&typename Archieve&
void serialize(Archieve &ar,const unsigned version) {
ar & d1_ & d2_;
&br&&br&我的主要看的是这个例子/Articles/225988/A-practical-guide-to-Cplusplus-serialization &br&可能是我对C++不熟,在编译过程中却是老是通不过。&br&我想了半天,死活想不出,结果看到一篇blog,看见其添加了一个导入了一个库文件我也尝试了一下 g++ -o main main.o -lboost_serialization 结果居然通过了,  &br&    看了一下save.txt 文件居然 将obj中的变量数值记录了下来。这个就是序列化?
使用C++进行对象序列化
什么是序列化
员在编写应用程序的时候往往需要将程序的某些数据存储在内存中,然后将其写入某个文件或是将它传输到网络中的另一台计算机上以实现通讯。这个将程序数据转化成能被存储并传输的格式的过程被称为“序列化”(Serialization),而它的逆过程则可被称为“反序列化”(Deserialization)。
简单来说,序列化就是将对象实例的状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它根据流重构对象。这两个过程结合起来,可以轻松地存储和传输数据。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。
为什么使用序列化2.1
哪些情况需要使用序列化2.1.1
以某种存储形式使自定义对象持久化
通过序列化,可以将对象的状态保持在存储媒体中,在以后能够重新创建精确的副本。我们经常需要将对象的字段值保存到磁盘中,并在以后检索此数据。尽管不使用序列化也能完成这项工作,但这种方法通常很繁琐而且容易出错,并且在需要跟踪对象的层次结构时,会变得越来越复杂。可以想象一下编写包含大量对象的大型业务应用程序的情形,程序员不得不为每一个对象编写,以便将字段和属性保存至磁盘以及从磁盘还原这些字段和属性。序列化提供了轻松实现这个目标的快捷方法。
2.1.2 将对象从一个地方传递到另一个地方
通常来说,对象仅在创建对象的应用程序域中有效。但是,序列化可以通过值将对象从一个应用程序域发送到另一个应用程序域中。例如,序列化可用于在ASP.NET中保存会话状态并将对象复制到Windows窗体的剪贴板中。序列化最重要的目的之一就是在网络上传输对象。
序列化的优势
在系统化的序列化方法出现之前,程序员如果想要将自定义的一个类的对象持久化地保存下来,并进行传输,可以采用以下这些方法:
l 由程序员自己实现保存对象数据的功能,针对每一个对象编写代码,将其数据存储下来。
l 将对象强制转换为char*或者void*类型的数据,然后进行数据的传输。
下面将从通用性、便捷性、灵活性和可移植性的角度来比较序列化相对于上述两种方法的优势。
2.2.1 通用性
如果由程序员自己实现保存对象数据的功能,那么对于每一个类的对象,程序员都要编写不同的代码,工作量很大,通用性不高。而序列化提供了一套流程化的方法,对于每一种类,都是大体一致的流程,提高了代码的通用性。
如果将对象强制转换为char*或void*类型的数据进行传输,那么必须预先得知该对象的大小以提前分配数组的空间。但是,如果该对象中存在可变长的数据结构,就无法准确地得知对象数据的大小了,只能预先估计一下。如果估计小了,可能会造成空间溢出,程序崩溃的后果;如果估计大了,又会造成空间的浪费。但是,如果使用序列化的方法,就能很好地解决可变长数据结构的问题。
2.2.2 便捷性
如果由程序员自己实现保存对象数据的功能,那么对于类中不同的数据结构,程序员都要编写相应的保存代码,简单的数据结构还好说,如果是具有多种层次的数据结构,代码的编写将越来越复杂,这样繁琐且容易出错。序列化提供了针对简单数据类型,以及字符串类型、STL容器、指针等种种数据类型的持久化的方法,只需简单地调用即可,具有很大的便捷性。
2.2.3 灵活性
序列化提供了若干种将对象数据持久化的格式,比如以简单文本格式保存、以XML格式保存、以SOAP格式保存、以二进制格式保存等等。还提供了多种保存持久化之后的对象的方式,比如保存到字符串、保存到文件等等,具有很大的灵活性。
2.2.4 可移植性
使用将对象强制转换为char*类型进行传输的方法,需要注意CPU字节序的问题。如果起始机器与目的机器的CPU字节序不同,就会造成目的机器读到的数据无法恢复成原来对象的问题。虽然可以通过将本地字节序转化为网络字节序进行传输,传到目的机器之后再将网络字节序转为本地字节序的方法解决这个问题,但是这就增加了程序员考虑问题的复杂性。序列化屏蔽了字节序的差异,使得被持久化对象的传输更具有可移植性。
此外,使用序列化还可以很好地跨平台。
3 我们的需求3.1 对基于OTT的数据库结构进行性能测试
在使用基于OTT的数据库结构的程序进行性能测试时,由于读入的PNR数据是XML格式的文档,所以,读入XML文件到内存,将其转为DOM树,继而将DOM树中的数据转化为OTT数据库所需要的对象结构,需要耗费大量的时间。如果把这部分时间算在程序的性能时间中,将导致测试出来的性能存在较大的误差。因此,最好的方式是,事先将XML格式的PNR数据转化为程序可用的对象,在程序运行时直接读入对象即可。这样可以将解析XML格式的PNR数据的时间与程序运行的时间分离开,从而保证了性能测试的准确性。而将PNR数据转为程序可用的对象保存下来,就是一个对象序列化的过程;程序读入保存对象的文件并将其恢复为原来的对象,这就是一个对象反序列化的过程。
3.2 只能使用某种特定类型进行数据传输的情况
在某些情况下,由于种种限制的约束,使得数据的传输只能使用某种特定的类型。比如,使用Tuxedo时,从客户端向服务端传数据只可以使用char*类型;比如,在使用共享内存传递数据时,只能采用连续的数组形式。在这些情况下,如果传输的数据是一个自定义类的对象的话,就会遇到挑战。一种做法是直接将该对象强制转化为所限定的类型,传到目的地之后再由限定的类型强制转为原来的类型。这种做法在性能上应该最快,但是使用这种方法必须得明确地知道所传出数据的长度,所以发送变长数据并不方便。此外,它还存在跨平台的兼容性问题。另一种做法就是利用对象序列化的方法,将对象保存为字节流,向目的地传输,在目的地再反序列化为自定义类的对象。这种方法相对比较通用,安全和规范,但是性能上可能不如前一种方法。
4 使用C++将对象进行序列化的几种方法
使用C++进行对象序列化的方法可以有以下三种:基于Boost库的方法;基于.Net Framework的方法;以及基于MFC的方法。本章将就三种方法的实现机制、实现步骤,以及注意事项进行说明。
由于我们的开发环境在Windows下,部署环境在Unix下,因此我们的开发需要使用两个平台都可以兼容的技术。经过验证,基于.Net和基于MFC的方法仅适用于Windows的环境,而Boost库在Windows和Unix下都有相应的版本,因此在项目中应优先考虑使用Boost库进行对象的序列化。尽管如此,本文中仍然列出使用.Net和MFC进行序列化的方法,以供参考。三种方法相应的代码实现的例子将附在之后。
4.1 使用Boost库4.1.1 实现机制
这里,我们用术语序列化(serialization)来表示将一组原始的C++数据结构表示为字节流达到可逆析构的目的。这样的系统可以用来在另一个程序环境中重新建立原来的数据结构。因此,它也可以作为对象持久性(object persistence),远程参数传递(remote parameter passing),或者其他特性的实现基础。在我们的系统中,将使用术语档案(archive)表示一个具体的字节流。档案可以是二进制文件,文本文件,XML文件,或者其他用户定义的类型。
Boost序列化库的目标是:
l 代码的可移植性–只依靠ANSI C++的特性。
l 代码的经济性–挖掘各种C++的特性如RTTI、模板、和多继承等等使用户容易使用并且代码短小。
l 类版本的独立性。–当一个类的定义改变时,老版本的类的档案仍然可以被导入新版本的类中。
l 指针的深度存储和恢复。–保存或恢复指针的同时保存或恢复指针指向的数据。
l 正确的处理多个指针指向相同对象时的问题。
l 对STL和其他常用模板类的序列化的直接支持。
l 数据的可移植性–在一个平台上建立的字节流在另一个平台上也应该是正确的。
l 序列化和档案格式的正交性–可以在不改变类的序列化部分时应用任何格式的文件作为档案。
l 支持非侵入(Non-intrusive)式的实现。类不需要从某个特定的类派生或者实现特定的成员函数。这对于我们不能或不愿意修改类的定义的情况时是相当必要的。
l 档案的接口应该足够简单使建立新类型的档案的工作变得轻松。
l 档案应该支持XML格式。
Boost中,与序列化有关的两个库是Archive库和Serialization库。
4.1.2 实现步骤
首先,为被序列化的类实现一个对应的serialize(Archive & ar, const unsigned int version)方法;
其次,构造boost::archive::text_oarchive类或其他archive输出类的对象,并将其关联到一个输出流,利用&&运算符将被序列化的对象输出到某个文档中;
最后,构造boost::archive::text_iarchive类或其他archive输入类的对象,并将其关联到一个输入流,读入数据,利用&&运算符会付出被序列化的对象。
4.1.3 注意事项
使用这种方法需要注意的是:
l Boost从1.32版本之后才提供对序列化的支持,所以一定要用版本在1.32之后的;
l Boost中的Serialization库需要编译之后得到库文件才能使用,并加入项目的附加依赖项中才可使用;
l 根据需要包含boost/serialization和boost/archive下的一些头文件。
4.2 使用.NET4.2.1 实现机制
.NET的运行时环境用来支持用户定义类型的流化的机制。它在此过程中,先将对象的公共字段和私有字段以及类的名称(包括类所在的程序集)转换为字节流,然后再把字节流写入数据流。在随后对对象进行反序列化时,将创建出与原对象完全相同的副本。
.Net框架对序列化机制具有非常好的支持,它提供了两个名字空间(namespace):System.Runtime.Serialization和System.Runtime.Serialization.Formatters以完成序列化机制的大部分功能。
序列化机制的实现是依靠格式器(Formatter)而完成的,它是一个从System.Runtime.Serialization.IFormatter继承下来的类的对象。格式器完成了将程序数据转化到能被存储并传输的格式的工作,同时也完成了将数据转化回来的工作。.Net框架为程序员提供了两种类型的格式器,一种通常是应用于桌面类型的应用程序的,它一个是System.Runtime.Serialization.Formatters.Binary.BinaryFormatter类的对象,而另一种则更主要的应用于.Net
Remoting和XML Web服务等领域的,它一个是System.Runtime.Serialization.Formatters.Soap.SoapFormatter类的对象。从它们的名称来看,不妨将它们分别称为二进制格式器和XML格式器。它们对应于.Net提供的两种序列化技术:
二进制序列化保持类型保真度,这对于在应用程序的不同调用之间保留对象的状态很有用。例如,通过将对象序列化到剪贴板,可在不同的应用程序之间共享对象,可以将对象序列化到流、磁盘、内存和网络等等。它的优点在于可以将所有的对象成员都保存下来,并且性能优于XML序列化。
XML 序列化仅序列化公共属性和字段,且不保持类型保真度。当您要提供或使用数据而不限制使用该数据的应用程序时,这一点是很有用的。由于 XML 是一个开放式标准,因此,对于通过 Web 共享数据而言,这是一个很好的选择。SOAP 同样是一个开放式标准,这使它也成为一个颇具吸引力的选择。它的优点在于互操作性好,可读性强。
4.2.2 实现步骤
使用.Net下的二进制序列化方法进行对象序列化的步骤如下:
首先,要使用 Serializable 属性对对象的类进行标记;
其次,利用BinaryFormatter的Serialize方法将对象写入到一个文件流中;
最后,利用BinaryFormatter的DeSerialize方法读取文件流,恢复对象。
4.2.3 注意事项
使用这种方法需要注意的是:
l 需要使用System::Runtime::Serialization::Formatters::Binary命名空间和 System::Runtime::Serialization命名空间;
l 被序列化的类在声明时必须标识[Serializable]属性;
l 所涉及的类必须是托管类,即类的声明前需要有ref关键字,用gcnew关键字表示在托管堆上分配内存,指针符号用^来标识等。
4.3 使用MFC4.3.1 实现机制
对象的序列化归根结底是将对象的数据写入载体,再重新读取为对象的过程。MFC中对数据的读写创造了十分好的支持,这使得我们可以十分方便的利用MFC的数据读写类来实现对象序列化的需要。
MFC 为数据读写了三个基本的类——CFile(CFile类)、CStdioFile(标准I/O文件类)、CArchive(CArchive类)。其中标准CStdioFile类提供相当于C的流式文件的功能,可以用文本或者二进制方式打开,可以被缓冲。CFile类提供了非缓冲的二进制输入输出文件,它既可以与CArchive类结合实现VisualC++设计中常用的文件序列化,也可以由设计者自己订制存储方案,实现数据的读写操作(此方法的兼容问题需要解决,保密性强)。CArchive类是VisualC++程序设计中最常用的文件处理的方法,CArchive类不仅可以实现简单数据结构的读写操作,还可以通过对CObiect类的派生实现对复杂数据结构的读写操作,因此,利用CArchive类,可以轻松实现任意数据结构的序列化。
4.3.2 实现步骤
实现序列化的的类需要满足一系列条件:
1. 该类需要从CObject类派生(可以是间接派生);
2. 在类中中进行DECLARE_SERIAL宏定义;
3. 类存在有缺省的构造函数;
4. 类中实现了Serialize(CArchive&)函数,并且在其中调用基类的序列化函数;
5. 使用IMPLEMENT_SERIAL宏指明类名及版本号。
满足了这些条件之后,就可以进行序列化与反序列化了。
序列化时,首先,实例化一个CArchive类的对象,将其与输出文件相关联;其次,利用CArchive类的&&运算符重载将需要序列化的对象保存在文件中。
反序列化时,将CArchive类的对象与保存对象的文件相关联;然后新建一个需要反序列化的对象,利用CArchive类的&&运算符重载将文件里的内容恢复到需要反序列化的对象中。
4.3.3 注意事项
使用这种方法需要注意的是:
l 需要包含afx.h头文件;
l 它不支持string类型的序列化,但是支持CString类型的序列化;
l 需要将项目属性中的MFC属性配置为“在共享DLL中使用MFC”或“在静态库中使用MFC”,否则编译时会报错。
5 使用Boost库进行对象序列化的关键技术5.1 基础
1、基本类型的存档和读取
对基本类型. 直接使用以下语句就可以完成存档或读取:
l 用 ar && data或ar & 写入存档
l 用 ar && data或ar & 从存档取出
2、自定义类型的存档和读取
对自定义类型. 则会调用 serialize() 函数,serialize 函数用来“存储/装载”其数据成员。这个处理采用递归的方式,直到所有包含在类中的数据“被存储/被装载”。
l 侵入式: t.serialize(ar, version)
l 非侵入式: serialize(ar, t, version)
3、所需包含的头文件:
l 以简单文本格式实现存档:text_oarchive和text_iarchive
l 宽字符的文本格式存档 :text_woarchive text_wiarchive
l xml存档:xml_oarchive xml_iarchive
l 使用宽字符的xml文档(用于utf-8)输出:xml_woarchive
xml_wiarchive
l 二进制的存档 (注意 二进制存档是不可移植的):binary_oarchive
binary_iarchive
5.2 侵入式和非侵入式
对于被序列化的类,有两种实现其对应的serialize方法的方式,一种是侵入式,即把serialize方法作为被序列化类的一个成员方法来实现;另一种是非侵入式,即将serialize方法放在另一个名字空间下,作为被序列化类的一个友元方法来实现。在不可修改被序列化的类的代码的情况下,应该采用非侵入式的方式。
侵入式的例子:
class MyPoint
friend class boost::serialization::
//侵入式版本的要加这个.
//存入和读取都使用下边的 serialize() 函数.
//其中的 Archive 是一个输入或输出的文档. 当输入的时候 & 为 && . 当输出的时候 & 为 &&.
template&class Archive&
void serialize(Archive& ar, const unsigned int version)
//序列化数据成员
MyPoint() {}
MyPoint(int x, int y) : mX(x), mY(y) {}
非侵入式的例子:
class MyPoint
// 注意关键字”friend”和多了一个类引用作参数
template&class Archive&
friend void serialize(Archive& ar, MyPoint&, unsigned int const);
MyPoint() {}
MyPoint(int x, int y) : mX(x), mY(y) {}
//非侵入式
namespace boost {
//实现放在这个名字空间下
namespace serialization {
template&class Archive&
void serialize(Archive & ar, MyPoint& p, const usigned int version)
ar & p.mX & p.mY;
//可以连着 &
//namespace 结束
5.3 派生类的序列化
对派生类进行序列化需要有一个前提,即它的父类必须也实现了serialize方法,也可以序列化。如果在派生类的父类没有实现serialize方法,仅对派生类进行序列化,将不能保存派生类从父类继承下来的数据信息,而仅能保存属于派生类自身的数据信息。
对派生类进行序列化的步骤是:
<p style="margin-top:0 margin-bottom:5 padding-top:0 padding-bottom:0 border:0 list-style: word-wrap: word-break: line-height:20 text-align: color:rgb(89,89,89); font-family:A letter-spacing:1p
&&&&推荐文章:
【上篇】【下篇】#include &stdafx.h&#include &boost/serialization/map.hpp&&#include &boost/archive/text_oarchive.hpp&#include &boost/archive/text_iarchive.hpp&#include &string&&#include &sstream&int _tmain(int argc, _TCHAR* argv[]){std::map&int, int& m_accountMm_accountMap[1] = 1;m_accountMap[2] = 2;std::std::boost::archive::text_oarchive oa(temp);oa&&m_accountMs = temp.str();std::istringstream iss(s);//通过构造函数对istringstream类进行赋&#20540;,可以将一个字符串变量的&#20540;传递给boost::archive::text_iarchive ia(iss);std::map&int, int& newMia && newMreturn 0;}
无相关信息
最新教程周点击榜
微信扫一扫本帖子已过去太久远了,不再提供回复功能。1394人阅读
Boost(6)
没有工作前,不知道序列化的作用。虽然那时候学习《Programming with MFC》的时候,也知道CArchive,CObject等东西,但是没有太意识到其作用。但是,如前所述,我工作的第一件事情,就是了解公司的序列化 类。从当时的一无所知,到现在也慢慢理解了一些序列化的作用了。说起来,自从工作以来因为当时做文件系统后后来的程序补丁,我应经在公司的序列化类以外额 外实现了两个独立的序列化类了,分别是文件序列化和内存序列化。
  这里也顺面讲讲序列化吧,虽然不算太难,也不算太复杂,但是这样越是基础的东西越是支持着程序:)没有还真不行。
   序列化的作用包括,实现操作系统,硬件平台无关的数据保存和传输。从网络传输角度来讲解决诸如大头,小头等问题。目前我自己的感受还有,对于保存数据和 读取数据使用同一套接口,简化了数据结构的管理,方便使用。虽然,序列化的作用一般是用来做永久保存的,在《深入浅出MFC》中,侯捷就将其中的序列化技 术讲解称为“VC&#43;&#43;六大关键技术”,事实上,序列化的作用不仅仅如此,比如我以前不就写过一个内存序列化类吧:)公司还有一个网络序列化类,即便在 MFC中,也有可以序列化的CMemFile,事实上,序列化还是一种二进制的交流方式。:)
  最典型的网络程序,就更好理解了,网络上 交流的其实都是二进制的数据,从一端到另外一端,大家要有统一的&#26684;式支持才能和谐-_-!不仅仅是字符串的编码需要一致,字节的顺序需要一致,每个位置是 什么&#20540;自然也需要一一指定好,一般而言,对于网络程序,在我们公司,对于序列化成一个包,我们叫打包,从一个网络包反序列化(&#20284;乎也有人叫串行化),我们 叫解包。
  这种二进制交流的方式不仅限于网络程序,任何程序间的交流都有可能用到,我碰到另外一个典型情况是一个Python脚本希望将 一些数据经过一段C&#43;&#43;程序,然后再放到另外一段Python脚本中去,这时当然可以通过Python的C API将所有的数据都一个一个转成C变量保存下来然后传出去,由C&#43;&#43;程序运行时保存,然后再通过Python的C API一一转成Python的变量,这样做有很多不好的地方,其一是Python脚本间传递的数据对于C&#43;&#43;程序来说不透明,任何改变都需要C&#43;&#43;程序进 行相应的更改,另外是每个变量都通过Python的C
API去转换效率不高。其实这里就可以利用序列化成二进制数据来传输,其上两个缺点都会消失。顺面提一下,在Python中可以通过struct库的 pack,unpack函数进行简单数据的序列化,通过marshal库来进行复杂对象的序列化(可是这个库好像已经不被推荐,但是我当时在实际工作中使 用的就是这个),有更先进的pickle(有更快的C语言版本cPickle),shelve可用。从这点来看,又会感叹Python的库实在是太多,往 往不是没有你想要的库,而是由于库太多,你不知道哪个好用-_-!
这里找到了一些序列化的库,MFC的序列化库不能在Linux下用,剩下可以尝试的还有s11n,CommonC&#43;&#43;,和boost的序列化库了。 特别要提到的就是boost的库。一个序列化的库也写了230多K,真是服了。基本上我在公司写的序列化类也就一个文件一个类,也就1K,包括了所有的基 本结构。很显然,boost的野心是很大的。出于对准标准库的尊敬。自然优先boost。特别要提到的是,Boost有所有我需要的东西-_-!并且我发 现Boost的ASIO库就是我以前计划完成的目标。以后有特别有文章详细提到。
  这里感谢为Boost库进行中文文档性工作的哥们,实在是感谢,虽然我常常以学英文为由去参看原文文档,甚至还阅读过基本原著,但是在文中引用的时候插入一篇的英文&#20284;乎是不太合适的,并且当我需要很快知道答案的时候,中文能够让我更快的处理,感谢你们。
  以下引号中内容摘自Boost中文文档1.37.0版本:
  这里有个对序列化比较正统的解释
   “这里,我们用术语 &serialization序列化& 来表示将任意一组C&#43;&#43;数据结构解构为一串字节的、可逆的过程。这样的系统可用于在另一个程序上下文中重新构建一个等价的结构。根据不同的上下文,它可以 用来实现对象持久化、远程参数传递或其它功能。在本系统中,我们使用术语 &archive存档& 来指代这个字节流的特定表现。它可以是一个二进制数据文件、文本文件、XML或其它由本库的用户所创建的东西。”
  注意,序列化的作用如我之前所述有:实现对象持久化、远程参数传递
  我们对于这个系统的目标是:
  代码的可移植性 - 只依赖于 ANSI C&#43;&#43; 所提供的功能。
编缉推荐阅读以下文章
序列化支持(4)—Boost的序列化库的强大之处 序列化支持(3)—Boost的序列化库的使用 序列化支持(1)—前言
  代码的经济性 - 使用C&#43;&#43;的一些特性,如 RTTI, 模板, 和多重继承等等,以使得代码更短也更易于使用。
  各个类定义版本的无关性。即当一个类的定义更改时,旧文件仍可导入到新版本的类中。
  深的指针保存和恢复。即指针的保存与恢复分别保存和恢复所指的数据。
  对共享数据指针的正确恢复。
  STL容器及其它常用模板的序列化。
  数据的可移植性 - 在一个平台上创建的字节流可以在另一平台上读出。
  类的序列化与存档&#26684;式的正交性。即任何文件&#26684;式都可用于保存任意一组C&#43;&#43;数据结构的序列化信息而无需调整。
  非介入性。可以对不作更改的类进行序列化。即不要求进行序列化的类派生自某个特定基类或者实现特定的成员函数。这一点对于要将序列化应用于某些我们不能或不愿修改的类库中的类来说是十分必要的。
  archive 的接口必须足够简单,以易于创建一种新的存档类型。
  archive 的接口又必须足够丰富,才可以创建出象XML这样风&#26684;的存档。
  野心够大,其描述的第1,7点很符合我的需要,第6点是属于额外的好处。
   我们公司的序列化方式是,对于已实现序列化的结构使用其结构的Serialize方法,对于基本结构使用序列化类的Serialize,因为序列化类已 经重载了基本结构的的Serialize实现。我曾经对比过这种方法和MFC的序列化方式,还有stream的使用方式,我感觉假如都使用stream那 样重载&&,&&操作符的方式是最能节省击键数的,并且也足够的形象,并且个人认为,在某种程序上来 说,stringstream就可以做一个简单的Archive实现来用。但是这里有一个比较不方便的就是,都需要先判断是存储还是读取,然后分别调用操
作符,这里就相当于多了一倍的工作量,而公司的方式(统一到Serialize函数),虽然多了函数名的输入,但是对于输入还是输出可以不关心,这是其很 大的优势。当时一下子还分不清孰优孰劣,但是出于亲近C&#43;&#43; 流实现的方式。碰到Boost的重载&操作符方式一下子傻了。。。。呵呵,听了太多的教条,太多的教导告诉我们不要重载操作符进行莫名奇妙的操 作,除了真正用到其操作符原始涵义的时候,我还真从来没有去重载过他们,这里算是见识到了,虽然是重载了与操作符进行序列化运算,有点扭曲,但是,一切是 简单就好,下面的示例你可以看到,这样兼有我上面所述的两种方案的优点。
编缉推荐阅读以下文章
序列化支持(4)—Boost的序列化库的强大之处 序列化支持(3)—Boost的序列化库的使用 序列化支持(1)—前言
  回想起工作当中用了多少CTRL-C,CTRL-V(yy,p)去实现该死的一行又一行的序列化啊,在我们公司吓死人的物品扩展属性中, 有60个以上的字段。也记不清多少次添加成员变量却忘写序列化函数导致的bug,虽然这样的bug都都容易找,但是都出在与同事联合调试的时候,还是浪费 了很多时间。Boost的这种方案仅仅也是简化了实现,并没有办法根除这一点,还是必须说明。虽然其提供了不介入的方式来完成序列化,但是本质上序列化函 数还是需要自己来写,以后要是有种方式能够为用户新添的任何结构或类进行序列化,而不需要用户进行额外的工作时,那才是完美的序列化方案。毕竟,越少的工
作,出错的机会也就越少。
  现在想起来,重复工作最多的几个地方在哪?其一,结构的拷贝构造函数和=操作符的重载,为了安全,公司都是一 个字段一个字段的写,累死人,也容易错。其二,就是一个字段一个字段的写序列化了。其三,目前还没有解决办法,数据库的操作,无论是MySQL的C API还是ODBC,都是有多少个字段(呵呵,多少个“?”)就得bind多少个结构的数据。也是累死人。想想我的两个记日志工作就心寒(其一就是日志服 务器,另外还有监控中心对整个服务器运行情况的日志记录),那个重复工作的啊。还好有vim:)以前还特意讲过怎么用vim来简化我的工作,没有vim我
都吐血了。最好用的就是q的记录功能和ctrl&#43;a的联合使用了(可惜Viemu不支持ctrl&#43;a)
  本来说,Boost的文档属于开 源库中最最详细的一列了,基本上跟着文档走就都能学会了,但是对于初学者来说可能有的地方太过简略,当然,对于熟悉boost的人来说那叫主题吐出,一针 见血。我这里主要摘文档中的例子来讲讲,偶尔发表一下自己的见解,有的地方也跟进实现去看看。毕竟原有的例子仅仅是很简单的。这里自然还是推荐任何学习者 都像我一样,调试其中的每一个例子,而不仅仅是看看而已。
本来来说,Boost的文档属于开源库中最最详细的一列了,基本上跟着文档走就都能学会了,但是对于初学者来说可能有的地方太过简略,当然,对于熟 悉boost的人来说那叫主题吐出,一针见血。我这里主要摘文档中的例子来讲讲,偶尔发表一下自己的见解,有的地方也跟进实现去看看。毕竟原有的例子仅仅 是很简单的。这里自然还是推荐任何学习者都像我一样,调试其中的每一个例子,而不仅仅是看看而已。
  关于Boost的编译和配置假如觉的麻烦,可以下一个自动下载安装的程序来完成,在windows下,从1.35开始我就一直使用此自动安装程序,安装和卸载非常方便,接下来需要做的就仅仅是简单的添加好工作路径就行了。
  以下例子如无特别说明都来自于boost的文档。
  例一:
// BoostLearn.cpp : 定义控制台应用程序的入口点。
#include &stdafx.h&
#include &fstream&
// 包含以简单文本&#26684;式实现存档的头文件
#include &boost/archive/text_oarchive.hpp&
#include &boost/archive/text_iarchive.hpp&
/////////////////////////////////////////////////////////////
// gps 座标
// 举例说明简单类型的序列化
class gps_position
    friend class boost::serialization::
    // 如果类Archive 是一个输出存档,则操作符& 被定义为&&.  同样,如果类Archive
    // 是一个输入存档,则操作符& 被定义为&&.
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
       ar & 
    int 
    int 
    float 
    gps_position(){};
    gps_position(int d, int m, float s) :
    degrees(d), minutes(m), seconds(s)
    {}
int main() {
    // 创建并打开一个输出用的字符存档
    std::ofstream ofs(&filename&);
    // 创建类实例
    const gps_position g(35, 59, 24.567f);
    // 保存数据到存档
       boost::archive::text_oarchive oa(ofs);
       // 将类实例写出到存档
       oa && g;
       // 在调用析构函数时将关闭存档和流
    // ... 晚些时候,将类实例恢复到原来的状态
    gps_position 
       // 创建并打开一个输入用的存档
       std::ifstream ifs(&filename&, std::ios::binary);
       boost::archive::text_iarchive ia(ifs);
       // 从存档中读取类的状态
       ia && 
       // 在调用析构函数时将关闭存档和流
    return 0;
编缉推荐阅读以下文章
序列化支持(4)—Boost的序列化库的强大之处 序列化支持(2)—Boost的序列化库 序列化支持(1)—前言
  首先,对于两个archive类我并不是很熟悉,这里摘其代码:
template&class Archive&
class interface_oarchive
protected:
    interface_oarchive(){};
    /////////////////////////////////////////////////////////
    // archive public interface
    typedef mpl::bool_&false& is_
    typedef mpl::bool_&true& is_
    // return a pointer to the most derived class
    Archive * This(){
        return static_cast&Archive *&(this);
    template&class T&
    const basic_pointer_oserializer *
    register_type(const T * = NULL){
        const basic_pointer_oserializer & bpos =
            boost::serialization::singleton&
                pointer_oserializer&Archive, T&
            &::get_const_instance();
        this-&This()-&register_basic_serializer(bpos.get_basic_serializer());
        return & 
    template&class T&
    Archive & operator&&(T & t){
        this-&This()-&save_override(t, 0);
        return * this-&This();
    // the & operator
    template&class T&
    Archive & operator&(T & t){
        #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
            return * this-&This() && const_cast&const T &&(t);
        #else
            return * this-&This() && t;
        #endif
编缉推荐阅读以下文章
序列化支持(4)—Boost的序列化库的强大之处 序列化支持(2)—Boost的序列化库 序列化支持(1)—前言
  这个函数的实现很有意思,利用了模板参数,然后强转,最后通过子类一层一层的传递,导致这里强转实际得到的是最深层次子类的指针。技巧性非常强:)虽然我实际中从来没有用到过-_-!这里相当于父类在实现某些函数的时候,直接使用子类的函数实现。
    Archive * This(){
        return static_cast&Archive *&(this);
  就例子中
   一句,其中函数来回调用,从子类到父类再到子类再到父类....#@$#@%#@相当的扭曲,利用的就是上面的This指针函数形式,为什么用这么多的 语句来实现本来一句简单的memcpy就能完成的功能,&#20540;得思考,也许要进一步对其整体的框架构造有所了解才行。但是这一点在文档中肯定是没有论述的,我 们寻找答案的唯一方法就是源代码了。
  先将其类互相之间的关系锊一下。
  text_oarchive继承自参数化类text_oarchive_impl,主要功能全由其提供。
   text_oarchive_impl参数化类继承自basic_text_oprimitive&std::ostream&与参数化类 basic_text_oarchive。text_oarchive_impl自身实现的代码主要是对各个字符串(包括 char*,wchar*,string,wstring)的序列化。
  text_oarchive_impl又是从参数化类basic_text_oprimitive和basic_text_oarchive继承过来。这里最好是画个UML图那就清晰了。但是由于我是如此的懒,所以我没有画-_-!
  其中basic_text_oprimitive的实现,告诉了我们,为什么需要This函数来调用子类的函数。
  通过跟踪源代码的boost::archive::text_oarchive oa(ofs);
   此句,会发现,最终ofs这个ofstream最终是传入到了这个参数化basic_text_oprimitive,并作为其引用成员变量os保存 的,然后basic_text_oprimitive C&#43;&#43;的basic类型的save函数重载,而save函数实际的实现又都是通过os的 &&操作符来实现的。
编缉推荐阅读以下文章
序列化支持(4)—Boost的序列化库的强大之处 序列化支持(2)—Boost的序列化库 序列化支持(1)—前言
  这里最引人注目的就是&操作符的重载,使得使用起来非常方便,兼有使用Serialize函数和&&,&&操作符的两种方案的好处。
  我刚开始工作的时候以为序列化最大的好处就是对类的类成员变量与普通变量都使用了统一的处理接口,这自然也是序列化所需要的基本功能之一。
  可序列化的成员
  一下例子从文档衍生而来,经过添加必要代码使其可以执行
// BoostLearn.cpp : 定义控制台应用程序的入口点。
#include &stdafx.h&
#include &fstream&
// 包含以简单文本&#26684;式实现存档的头文件
#include &boost/archive/text_oarchive.hpp&
#include &boost/archive/text_iarchive.hpp&
/////////////////////////////////////////////////////////////
// gps 座标
// 举例说明简单类型的序列化
class gps_position
    friend class boost::serialization::
    // 如果类Archive 是一个输出存档,则操作符& 被定义为&&.  同样,如果类Archive
    // 是一个输入存档,则操作符& 被定义为&&.
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
       ar & 
    int 
    int 
    float 
    gps_position()
       degrees = 0;
       minutes = 0;
       seconds = 0.0;
    };
    gps_position(int d, int m, float s) :
    degrees(d), minutes(m), seconds(s)
    {}
class bus_stop
    friend class boost::serialization::
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
    gps_position 
    gps_position 
    bus_stop(){ }
    bus_stop(const gps_position & lat_, const gps_position & long_) :
        latitude(lat_), longitude(long_){ }
        
    virtual ~bus_stop(){ }
int main() {
    // 创建并打开一个输出用的字符存档
    std::ofstream ofs(&busfile&);
    // 创建类实例
    const gps_position latitude(1, 2, 3.3f);
    const gps_position longitude(4, 5, 6.6f);
    bus_stop stop(latitude, longitude);
    // 保存数据到存档
       boost::archive::text_oarchive oa(ofs);
       // 将类实例写出到存档
       oa && 
        // 在调用析构函数时将关闭存档和流
    // ... 晚些时候,将类实例恢复到原来的状态
    bus_stop 
       // 创建并打开一个输入用的存档
       std::ifstream ifs(&busfile&, std::ios::binary);
       boost::archive::text_iarchive ia(ifs);
       // 从存档中读取类的状态
       ia && 
       // 在调用析构函数时将关闭存档和流
    return 0;
编缉推荐阅读以下文章
序列化支持(4)—Boost的序列化库的强大之处 序列化支持(2)—Boost的序列化库 序列化支持(1)—前言
  这样,对于gps_positon这样的类成员变量,由于为其写过序列化函数了,就可以直接将其序列化
  在这里是用:
       ar & 
       ar & 
  的形式,这就是我刚开始唯一知道的序列化的好处。
  当然,对于派生的类,应该也能调用基类的序列化函数,这在C&#43;&#43;中也应该属于序列化的基本功能。
  见下例:
// BoostLearn.cpp : 定义控制台应用程序的入口点。
#include &stdafx.h&
#include &fstream&
// 包含以简单文本&#26684;式实现存档的头文件
#include &boost/archive/text_oarchive.hpp&
#include &boost/archive/text_iarchive.hpp&
/////////////////////////////////////////////////////////////
// gps 座标
// 举例说明简单类型的序列化
class gps_position
    friend class boost::serialization::
    // 如果类Archive 是一个输出存档,则操作符& 被定义为&&.  同样,如果类Archive
    // 是一个输入存档,则操作符& 被定义为&&.
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
       ar & 
    int 
    int 
    float 
    gps_position()
       degrees = 0;
       minutes = 0;
       seconds = 0.0;
    };
    gps_position(int d, int m, float s) :
    degrees(d), minutes(m), seconds(s)
    {}
class bus_stop
    friend class boost::serialization::
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
    gps_position 
    gps_position 
    bus_stop(){ }
    bus_stop(const gps_position & lat_, const gps_position & long_) :
        latitude(lat_), longitude(long_){ }
        
    virtual ~bus_stop(){ }
class bus_stop_corner : public bus_stop
    friend class boost::serialization::
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       // 序列化基类信息
       ar & boost::serialization::base_object&bus_stop&(*this);
       ar & street1;
       ar & street2;
    std::string street1;
    std::string street2;
    bus_stop_corner(){}
    bus_stop_corner(const gps_position & lat_, const gps_position & long_,
       const std::string & s1_, const std::string & s2_
       ) :
    bus_stop(lat_, long_), street1(s1_), street2(s2_)
    {}
    virtual std::string description() const
       return street1 &#43; & and & &#43; street2;
int main() {
    // 创建并打开一个输出用的字符存档
    std::ofstream ofs(&bus_corner&);
    // 创建类实例
    const gps_position latitude(1, 2, 3.3f);
    const gps_position longitude(4, 5, 6.6f);
    bus_stop_corner stop_corner(latitude, longitude, &corn1&, &corn2&);
    // 保存数据到存档
       boost::archive::text_oarchive oa(ofs);
       // 将类实例写出到存档
       oa && stop_
       // 在调用析构函数时将关闭存档和流
    // ... 晚些时候,将类实例恢复到原来的状态
    bus_stop_corner new_stop_
       // 创建并打开一个输入用的存档
       std::ifstream ifs(&bus_corner&, std::ios::binary);
       boost::archive::text_iarchive ia(ifs);
       // 从存档中读取类的状态
       ia && new_stop_
       // 在调用析构函数时将关闭存档和流
    return 0;
  可以尝试调试程序,这里为了简化代码,我没有将信息输出了。
   至此,我们已经有了序列化需要的基本功能了,至于其他更多复杂的结构不过就是此种方式的组合而已。另外,此种使用方式已经超过了我公司的序列化类 -_-!那个类实现是非常简单的,但是功能&#20284;乎也是如此的弱,但是这里的超过不过是通过&符号的重载来简化Serialize函数的调用而已,还 算不上什么质的飞跃。下面看质的飞跃所在。
 1.      非介入式版本
  感觉实际使用中我还没有碰到过,既然需要完全的public才能还原数据,那么介入不介入好像影响也不大了,除非碰到一个东西是别的公司写的,不让改,我是还没有碰到这样的情况。
  从这里开始见识Boost序列化库的强大。
  2.      指针的序列化:
  下面的例子为文档中例子的简化,并添加必要部分以方便运行及演示。
// BoostLearn.cpp : 定义控制台应用程序的入口点。
#include &stdafx.h&
#include &fstream&
// 包含以简单文本&#26684;式实现存档的头文件
#include &boost/archive/text_oarchive.hpp&
#include &boost/archive/text_iarchive.hpp&
/////////////////////////////////////////////////////////////
// gps 座标
// 举例说明简单类型的序列化
class gps_position
    friend class boost::serialization::
    // 如果类Archive 是一个输出存档,则操作符& 被定义为&&.  同样,如果类Archive
    // 是一个输入存档,则操作符& 被定义为&&.
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
       ar & 
    int 
    int 
    float 
    gps_position()
       degrees = 0;
       minutes = 0;
       seconds = 0.0;
    };
    gps_position(int d, int m, float s) :
    degrees(d), minutes(m), seconds(s)
    {}
class bus_stop
    friend class boost::serialization::
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
    gps_position 
    gps_position 
    bus_stop(){ }
    bus_stop(const gps_position & lat_, const gps_position & long_) :
        latitude(lat_), longitude(long_){ }
        
    virtual ~bus_stop(){ }
class bus_stop_corner : public bus_stop
    friend class boost::serialization::
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       // 序列化基类信息
       ar & boost::serialization::base_object&bus_stop&(*this);
       ar & street1;
       ar & street2;
    std::string street1;
    std::string street2;
    bus_stop_corner(){}
    bus_stop_corner(const gps_position & lat_, const gps_position & long_,
       const std::string & s1_, const std::string & s2_
       ) :
    bus_stop(lat_, long_), street1(s1_), street2(s2_)
    {}
    virtual std::string description() const
       return street1 &#43; & and & &#43; street2;
class bus_route
    friend class boost::serialization::
    bus_stop_corner * stops[2];
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       int i;
       for(i = 0; i & 2; &#43;&#43;i)
           ar & stops[i];
    bus_route(bus_stop_corner *apStop1, bus_stop_corner *apStop2)
       stops[0] = apStop1;
       stops[1] = apStop2;
    bus_route(){}
int main() {
    // 创建并打开一个输出用的字符存档
    std::ofstream ofs(&bus_route&);
    // 创建类实例
    const gps_position latitude(1, 2, 3.3f);
    const gps_position longitude(4, 5, 6.6f);
    bus_stop_corner *lpStop1 = new bus_stop_corner(latitude, longitude, &corn1&, &corn2&);
    bus_stop_corner *lpStop2 = new bus_stop_corner(latitude, longitude, &corn3&, &corn4&);
    bus_route route(lpStop1, lpStop2);
    // 保存数据到存档
       boost::archive::text_oarchive oa(ofs);
       // 将类实例写出到存档
       oa && 
       // 在调用析构函数时将关闭存档和流
    // ... 晚些时候,将类实例恢复到原来的状态
    bus_route new_
       // 创建并打开一个输入用的存档
       std::ifstream ifs(&bus_route&, std::ios::binary);
       boost::archive::text_iarchive ia(ifs);
       // 从存档中读取类的状态
       ia && new_
       // 在调用析构函数时将关闭存档和流
    delete lpStop1;
    delete lpStop2;
    return 0;
编缉推荐阅读以下文章
序列化支持(3)—Boost的序列化库的使用 序列化支持(2)—Boost的序列化库 序列化支持(1)—前言
  这里的强大之处在于指针反序列化的时候自动的分配了内存,这样简化了很多的操作,当然,这样就会存在文档中提出的内存泄露的问题,在此例 中的确存在,反序列化时分配了内存但是却没有合理的地方去释放,由外部去释放感觉并不是太妥当,boost文档中的建议是使用智能指针,比如 share_ptr。这个例子我们放到最后,先看看利用普通类的一条确保内存分配并不泄露的原则,哪里分配的哪里释放,对象自己管理自己的内存。
  见下例:(此例为文档中没有的)
// BoostLearn.cpp : 定义控制台应用程序的入口点。
#include &stdafx.h&
#include &fstream&
// 包含以简单文本&#26684;式实现存档的头文件
#include &boost/archive/text_oarchive.hpp&
#include &boost/archive/text_iarchive.hpp&
/////////////////////////////////////////////////////////////
// gps 座标
// 举例说明简单类型的序列化
class gps_position
    friend class boost::serialization::
    // 如果类Archive 是一个输出存档,则操作符& 被定义为&&.  同样,如果类Archive
    // 是一个输入存档,则操作符& 被定义为&&.
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
       ar & 
    int 
    int 
    float 
    gps_position()
       degrees = 0;
       minutes = 0;
       seconds = 0.0;
    };
    gps_position(int d, int m, float s) :
    degrees(d), minutes(m), seconds(s)
    {}
class bus_stop
    friend class boost::serialization::
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
    gps_position 
    gps_position 
    bus_stop(){ }
    bus_stop(const gps_position & lat_, const gps_position & long_) :
        latitude(lat_), longitude(long_){ }
        
    virtual ~bus_stop(){ }
class bus_stop_corner : public bus_stop
    friend class boost::serialization::
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       // 序列化基类信息
       ar & boost::serialization::base_object&bus_stop&(*this);
       ar & street1;
       ar & street2;
    std::string street1;
    std::string street2;
    bus_stop_corner(){}
    bus_stop_corner(const gps_position & lat_, const gps_position & long_,
       const std::string & s1_, const std::string & s2_
       ) :
    bus_stop(lat_, long_), street1(s1_), street2(s2_)
    {}
    virtual std::string description() const
       return street1 &#43; & and & &#43; street2;
class bus_route
    friend class boost::serialization::
    // 这里将数组缩减到,是为了减少编码量并显得更清楚,毕竟说明清楚情况就好了
    bus_stop_corner * stops[2];
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       for(int i = 0; i & 2; &#43;&#43;i)
           ar & stops[i];
    bus_route(const bus_stop_corner& aoStop1, const bus_stop_corner& aoStop2)
       stops[0] = new bus_stop_corner(aoStop1);
       stops[1] = new bus_stop_corner(aoStop2);
    bus_route()
       stops[0] = new bus_stop_
       stops[1] = new bus_stop_
    ~bus_route()
       for(int i = 0; i & 2; &#43;&#43;i)
       {
           delete stops[i];
       }
int main() {
    // 创建并打开一个输出用的字符存档
    std::ofstream ofs(&bus_route&);
    // 创建类实例
    const gps_position latitude(1, 2, 3.3f);
    const gps_position longitude(4, 5, 6.6f);
    bus_stop_corner loStop1(latitude, longitude, &corn1&, &corn2&);
    bus_stop_corner loStop2(latitude, longitude, &corn3&, &corn4&);
    bus_route route(loStop1, loStop2);
    // 保存数据到存档
       boost::archive::text_oarchive oa(ofs);
       // 将类实例写出到存档
       oa && 
       // 在调用析构函数时将关闭存档和流
    // ... 晚些时候,将类实例恢复到原来的状态
    bus_route new_
       // 创建并打开一个输入用的存档
       std::ifstream ifs(&bus_route&, std::ios::binary);
       boost::archive::text_iarchive ia(ifs);
       // 从存档中读取类的状态
       ia && new_
       // 在调用析构函数时将关闭存档和流
    return 0;
编缉推荐阅读以下文章
序列化支持(3)—Boost的序列化库的使用 序列化支持(2)—Boost的序列化库 序列化支持(1)—前言
  其实在一般情况下,只需要遵循了上述的原则,内存泄露问题一般不会存在,但是这里有个疑问就是,当指针分配了内存,boost序列化的时候是不是还是傻傻的去重新分配一次内存,然后导致第一次分配的内存没有正常释放,导致内存泄露呢?我们来检验一样。
  当new_route调用默认构造函数分配内存时,数组中指针的地址如下:
[0] = 0x003b7090 {street1=&& street2=&& }
[1] = 0x003bafb0 {street1=&& street2=&& }
  反序列化后:
[0] = 0x003b9150 {street1=&corn1& street2=&corn2& }
[1] = 0x003b9268 {street1=&corn3& street2=&corn4& }
   经证实。boost在指针已经分配过内存的情况下仍然重新为指针分配了一次内存,这一点够傻的,那么,这样傻的行为有没有一点保护呢?比如首先判断一下 指针是否为NULL,然后先delete再new呢?虽然这样的操作好像更傻。当时总好过与内存泄露,验证一下的方法很简单,在ia && new_一句执行前在bus_stop_corner的析构函数上加断电,假如boost调用了delete,其析构一定会发生,事实是残酷 的。假如事先为指针分配了内存,那么必然发生内存的泄露。boost根本不管指针是否已经分配过内存,直接忽略,并重新分配内存。
  其实,一般而言,需要反序列化的时候,提供一个空的对象也是比较合理的,毕竟这是一个还原对象的过程,所以程序改成下面例子这样就可以在不使用智能指针的时候避免内存泄露了。
// BoostLearn.cpp : 定义控制台应用程序的入口点。
#include &stdafx.h&
#include &fstream&
// 包含以简单文本&#26684;式实现存档的头文件
#include &boost/archive/text_oarchive.hpp&
#include &boost/archive/text_iarchive.hpp&
#include &cstdlib&
using namespace 
/////////////////////////////////////////////////////////////
// gps 座标
// 举例说明简单类型的序列化
class gps_position
    friend class boost::serialization::
    // 如果类Archive 是一个输出存档,则操作符& 被定义为&&.  同样,如果类Archive
    // 是一个输入存档,则操作符& 被定义为&&.
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
       ar & 
    int 
    int 
    float 
    gps_position()
       degrees = 0;
       minutes = 0;
       seconds = 0.0;
    };
    gps_position(int d, int m, float s) :
    degrees(d), minutes(m), seconds(s)
    {}
class bus_stop
    friend class boost::serialization::
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
    gps_position 
    gps_position 
    bus_stop(){ }
    bus_stop(const gps_position & lat_, const gps_position & long_) :
        latitude(lat_), longitude(long_){ }
        
    virtual ~bus_stop(){ }
class bus_stop_corner : public bus_stop
    friend class boost::serialization::
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       // 序列化基类信息
       ar & boost::serialization::base_object&bus_stop&(*this);
       ar & street1;
       ar & street2;
    std::string street1;
    std::string street2;
    bus_stop_corner(){}
    bus_stop_corner(const gps_position & lat_, const gps_position & long_,
       const std::string & s1_, const std::string & s2_
       ) :
    bus_stop(lat_, long_), street1(s1_), street2(s2_)
    {}
    virtual std::string description() const
       return street1 &#43; & and & &#43; street2;
    ~bus_stop_corner()
class bus_route
    friend class boost::serialization::
    // 这里将数组缩减到,是为了减少编码量并显得更清楚,毕竟说明清楚情况就好了
    bus_stop_corner * stops[2];
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       for(int i = 0; i & 2; &#43;&#43;i)
           ar & stops[i];
    bus_route(const bus_stop_corner& aoStop1, const bus_stop_corner& aoStop2)
       stops[0] = new bus_stop_corner(aoStop1);
       stops[1] = new bus_stop_corner(aoStop2);
    bus_route()
       stops[0] = NULL;
       stops[1] = NULL;
    ~bus_route()
       for(int i = 0; i & 2; &#43;&#43;i)
       {
           if(stops[i] != NULL)
           {
              delete stops[i];
           }
       }
int main() {
    // 创建并打开一个输出用的字符存档
    std::ofstream ofs(&bus_route&);
    // 创建类实例
    const gps_position latitude(1, 2, 3.3f);
    const gps_position longitude(4, 5, 6.6f);
    bus_stop_corner loStop1(latitude, longitude, &corn1&, &corn2&);
    bus_stop_corner loStop2(latitude, longitude, &corn3&, &corn4&);
    bus_route route(loStop1, loStop2);
    // 保存数据到存档
       boost::archive::text_oarchive oa(ofs);
       // 将类实例写出到存档
       oa && 
       // 在调用析构函数时将关闭存档和流
    // ... 晚些时候,将类实例恢复到原来的状态
    bus_route new_
       // 创建并打开一个输入用的存档
       std::ifstream ifs(&bus_route&, std::ios::binary);
       boost::archive::text_iarchive ia(ifs);
       // 从存档中读取类的状态
       ia && new_
       // 在调用析构函数时将关闭存档和流
    return 0;
编缉推荐阅读以下文章
序列化支持(3)—Boost的序列化库的使用 序列化支持(2)—Boost的序列化库 序列化支持(1)—前言
  这里的bus_route类有指针和内存分配但是没有合理的拷贝构造函数和operator=重载,仅仅只是作为演示使用,实际中这里几 乎是必须的,即使不需要使用到复制也应该将此两个函数放入private中以表示禁止复制,以防误用。(比如std的I/O stream类实现即是如此)
  改成上述例子中的形式后,需要注意的是反序列化前一定要是一个空对象,假如以前有分配内存的话需要提前释 放到,还好这些都可以很简单的由对象本身所保证。这一点可能的错误应用应该算是Boost为了易用性而导致的。。。。基本掌握了还算能接受,起码对于指针 的序列化还是简单了很多,仅仅是需要多注意一下传入的必须是空的指针就行。
  Boost作为准标准库,虽然有的时候显得有点庞大,但是 STL的搭配,和众多新Boost特性的搭配是非常的默契(不知道这个词是否恰当)。从上面的序列化就可以看出来,序列化是完全融入原有的C&#43;&#43; stream体系的,这点我们公司的序列化根本没有办法比。谈到这点就是想说,其实包括auto_ptr甚至shared_ptr在内的智能指针,包括 vector,map等STL容器,甚至连array在内。
  这里是使用智能指针的两个例子,但是boost的serialize库如此 偏心。share_ptr是内嵌在库里面的,而C&#43;&#43;标准库的auto_ptr竟然没有内嵌在库里面,仅仅是在demo中给出实现。也就是说,明明实现 了,就是不想放到库里面去。如此不推荐使用auto_ptr的做法,完全见证了我当时强烈感叹的auto_ptr的异类。我就不知道他是怎么混进标准库 的。
  以下是智能指针的使用示例代码:
// BoostLearn.cpp : 定义控制台应用程序的入口点。
#include &stdafx.h&
#include &fstream&
// 包含以简单文本&#26684;式实现存档的头文件
#include &boost/archive/text_oarchive.hpp&
#include &boost/archive/text_iarchive.hpp&
#include &cstdlib&
#include &boost/tr1/memory.hpp&
#include &vector&
#include &map&
#include &boost/tr1/unordered_map.hpp&
#include &memory&
#include &boost/serialization/shared_ptr.hpp&
using namespace 
using namespace 
using namespace boost::
#include &boost/serialization/split_free.hpp&
namespace boost {
    namespace serialization {
       /////////////////////////////////////////////////////////////
       // implement serialization for auto_ptr&T&
       // note: this must be added to the boost namespace in order to
       // be called by the library
       template&class Archive, class T&
       inline void save(
           Archive & ar,
           const std::auto_ptr&T& &t,
           const unsigned int file_version
           ){
              // only the raw pointer has to be saved
              // the ref count is rebuilt automatically on load
              const T * const tx = t.get();
              ar && 
       }
       template&class Archive, class T&
       inline void load(
           Archive & ar,
           std::auto_ptr&T& &t,
           const unsigned int file_version
           ){
              T *pT
              ar && pT
              // note that the reset automagically maintains the reference count
#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
              t.release();
              t = std::auto_ptr&T&(pTarget);
              t.reset(pTarget);
       }
       // split non-intrusive serialization function member into separate
       // non intrusive save/load member functions
       template&class Archive, class T&
       inline void serialize(
           Archive & ar,
           std::auto_ptr&T& &t,
           const unsigned int file_version
           ){
               boost::serialization::split_free(ar, t, file_version);
       }
    } // namespace serialization
} // namespace boost
/////////////////////////////////////////////////////////////
// gps 座标
// 举例说明简单类型的序列化
class gps_position
    friend class boost::serialization::
    // 如果类Archive 是一个输出存档,则操作符& 被定义为&&.  同样,如果类Archive
    // 是一个输入存档,则操作符& 被定义为&&.
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
       ar & 
    int 
    int 
    float 
    gps_position()
       degrees = 0;
       minutes = 0;
       seconds = 0.0;
    };
    gps_position(int d, int m, float s) :
    degrees(d), minutes(m), seconds(s)
    {}
class bus_stop
    friend class boost::serialization::
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & 
       ar & 
    gps_position 
    gps_position 
    bus_stop(){ }
    bus_stop(const gps_position & lat_, const gps_position & long_) :
        latitude(lat_), longitude(long_){ }
        
    virtual ~bus_stop(){ }
class bus_stop_corner : public bus_stop
    friend class boost::serialization::
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       // 序列化基类信息
       ar & boost::serialization::base_object&bus_stop&(*this);
       ar & street1;
       ar & street2;
    std::string street1;
    std::string street2;
    bus_stop_corner(){}
    bus_stop_corner(const gps_position & lat_, const gps_position & long_,
       const std::string & s1_, const std::string & s2_
       ) :
    bus_stop(lat_, long_), street1(s1_), street2(s2_)
    {}
    virtual std::string description() const
       return street1 &#43; & and & &#43; street2;
    ~bus_stop_corner()
class bus_route
    friend class boost::serialization::
    // 这里将数组缩减到,是为了减少编码量并显得更清楚,毕竟说明清楚情况就好了
    shared_ptr&bus_stop_corner& msptrBusS
    auto_ptr&bus_stop_corner& maptrBusS
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & msptrBusS
       ar & maptrBusS
    bus_route(const bus_stop_corner& aoStop1, const bus_stop_corner& aoStop2):
      msptrBusStop(new bus_stop_corner(aoStop1)),
       maptrBusStop(new bus_stop_corner(aoStop2))
    bus_route()
    ~bus_route()
int main() {
    // 创建并打开一个输出用的字符存档
    std::ofstream ofs(&bus_route&);
    // 创建类实例
    const gps_position latitude(1, 2, 3.3f);
    const gps_position longitude(4, 5, 6.6f);
    bus_stop_corner loStop1(latitude, longitude, &corn1&, &corn2&);
    bus_stop_corner loStop2(latitude, longitude, &corn3&, &corn4&);
    bus_route route(loStop1, loStop2);
    // 保存数据到存档
       boost::archive::text_oarchive oa(ofs);
       // 将类实例写出到存档
       oa && 
       // 在调用析构函数时将关闭存档和流
    // ... 晚些时候,将类实例恢复到原来的状态
    bus_route new_
       // 创建并打开一个输入用的存档
       std::ifstream ifs(&bus_route&, std::ios::binary);
       boost::archive::text_iarchive ia(ifs);
       // 从存档中读取类的状态
       ia && new_
       // 在调用析构函数时将关闭存档和流
    return 0;
编缉推荐阅读以下文章
序列化支持(3)—Boost的序列化库的使用 序列化支持(2)—Boost的序列化库 序列化支持(1)—前言
  至于剩下的STL容器之类的,由于和普通的成员变量都看不出区别了,我弄个简单的示例说明一下就好了,按原文档的话来说是:
  The serialization library contains code for serialization of all STL classes.
  还不够吗?
   从上面的例子上已经可以看出std::string肯定没有问题了,我只想知道一个东西,tr1的unordered_map实现了没有。但是非常遗 憾。呵呵,没有实现,不过vector和list的实现自然是没有问题,一下给出例子,这里需要说明的是,对于STL来说,可能是考虑到每个实现都比较 大,所以在使用了相应的容器后,需要包含序列化相应的头文件,比如vector就是boost/serialization/vector.hpp,依次 类推,这点share_ptr的示例其实就已经使用了,但是没有特别说明。
// BoostLearn.cpp : 定义控制台应用程序的入口点。
#include &stdafx.h&
#include &fstream&
// 包含以简单文本&#26684;式实现存档的头文件
#include &boost/archive/text_oarchive.hpp&
#include &boost/archive/text_iarchive.hpp&
#include &cstdlib&
#include &boost/tr1/memory.hpp&
#include &vector&
#include &map&
#include &memory&
#include &boost/serialization/vector.hpp&
using namespace 
using namespace 
using namespace boost::
class CSerializeAble
    std::vector&int& miV
    friend class boost::serialization::
    template&class Archive&
    void serialize(Archive & ar, const unsigned int version)
       ar & miV
int main() {
    // 创建并打开一个输出用的字符存档
    std::ofstream ofs(&contains&);
    CSerializeAble loSA;
    loSA.miVec.push_back(1);
    loSA.miVec.push_back(2);
    loSA.miVec.push_back(3);
    // 保存数据到存档
       boost::archive::text_oarchive oa(ofs);
       // 将类实例写出到存档
       oa && loSA;
       // 在调用析构函数时将关闭存档和流
    // ... 晚些时候,将类实例恢复到原来的状态
    CSerializeAble lonewSA;
       // 创建并打开一个输入用的存档
       std::ifstream ifs(&contains&, std::ios::binary);
       boost::archive::text_iarchive ia(ifs);
       // 从存档中读取类的状态
       ia && lonewSA;
       // 在调用析构函数时将关闭存档和流
    return 0;
  到了这里,已经可以看到Boost::Serialize的强大了,这里还想说明的是,虽然文档中有std::list&bus_stop *&这样的例子,但是实际上我这样做却无法编译通过。这点很奇怪
   然后,Boost::Serialize由于是完全融入C&#43;&#43;的IOStream系统的,所以,只要你实现你自己的Stream,比如文档中提到的 XML系统,你就可以实现任意的方式保存你序列化的数据。这样的开放性也是&#20540;得一提的,光是这一点都不是一般的非“准标准库”可以比拟的。序列化大概就讲 这么多吧。序列化在公司只用了半天去了解,但是自己这段时间工作太忙,结果学习Boost的序列化库的使用,还不是看其实现,就用了这么久,真是无奈。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:222170次
积分:2482
积分:2482
排名:第12267名
转载:107篇
评论:41条
(2)(2)(4)(4)(3)(2)(1)(1)(2)(1)(1)(2)(3)(2)(2)(6)(1)(5)(14)(4)(3)(4)(5)(4)(6)(9)(4)(15)}

我要回帖

更多关于 boost程序库探秘 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信