對于核心數(shù)據(jù)相對比較集中的應(yīng)用程序來說,serialization機(jī)制可以直接充當(dāng)文檔保存與打開功能的實(shí)現(xiàn)工具,這也是很多成熟的應(yīng)用程序framework都提供serialization支持的原因
但是個(gè)人認(rèn)為,serialization最精彩的用處在于保存現(xiàn)場,比如在探索性的科研應(yīng)用程序開發(fā)過程中,很可能一部分算法已經(jīng)固定下來,其余的有待進(jìn)一步探索,而確定下來的部分有可能十分time consuming,如果每次改一下算法都要從頭計(jì)算,就會很費(fèi)時(shí)間,長期下去對工作情緒會有很大影響,這時(shí)候可以用serialization把每一步的結(jié)果存成文件,下次啟動時(shí)任選一個(gè)開始新的計(jì)算。

Boost的Serialization庫是一個(gè)十分強(qiáng)大的工具,它文檔中提到的11個(gè)開發(fā)目標(biāo)列舉如下:
1.代碼移植性,只依賴于ANSI C++標(biāo)準(zhǔn)
2.代碼簡潔性,的確運(yùn)用Boost::Serialization所需要的代碼量很小
3.每個(gè)類有自己獨(dú)立的版本控制,以保證舊的save結(jié)果可以被新的程序load回來
4.深度指針save與load,不僅serialize指針本身,而且包括它指向的對象數(shù)據(jù)
5.多個(gè)指針指向同一個(gè)對象不會被serialize多次
6.對常用STL容器的支持
7.串行數(shù)據(jù)的平臺移植性
8.類如何被串行化與串行數(shù)據(jù)按何種格式存儲相互無關(guān)
9.非侵入性,這對于數(shù)據(jù)中使用了第三方類庫的情形很有效

最后兩個(gè)沒有理解,希望高人指點(diǎn)
10.The archive interface must be simple enough to easily permit creation of a new type of archive.
11.The archive interface must be rich enough to permit the creation of an archive that presents serialized data as XML in a useful manner.

下面是我試用Boost::Serialization的記錄

第一個(gè)例子

假設(shè)有這樣一個(gè)類需要串行化

?

class ?Data
{
public :
????
int ?mInt;
}
;

?

這里為了簡化起見,成員變量都設(shè)成public了,串行化的代碼如下

?

?1 #include? < fstream >
?2
?3 // ?fewest?include?headers
?4 #include? < boost / archive / text_iarchive.hpp >
?5 #include? < boost / archive / text_oarchive.hpp >
?6
?7 // ?use?this?to?ease?the?archive?selection
?8 typedef?boost::archive::text_iarchive?iarchive;
?9 typedef?boost::archive::text_oarchive?oarchive;
10
11 class ?Data
12 {
13 ????friend? class ?boost::serialization::access;
14
15 protected :
16
17 ????template < class ?Archive >
18 ???? void ?serialize(Archive? & ?ar,? const ?unsigned? int ? /* ?file_version? */ )
19 ???? {
20 ????????ar? & ?mInt;
21 ????}

22
23 public :
24
25 ???? int ?mInt;
26
27 ???? static ? void ?saveData( const ?Data & ?obj,?std:: string ?fileName)
28 ???? {
29 ????????std::ofstream?ofs(fileName.c_str());
30 ????????oarchive?oa(ofs);
31 ????????oa? << ?obj;
32 ????}

33
34 ???? static ? void ?loadData(Data & ?obj,?std:: string ?fileName)
35 ???? {
36 ????????std::ifstream?ifs(fileName.c_str());
37 ????????iarchive?ia(ifs);
38 ????????ia? >> ?obj;
39 ????}

40 }
;
41
42 void ?main()
43 {
44 ????Data?d1;
45 ????d1.mInt? = ? 3 ;
46
47 ????Data::saveData(d1,? " output.txt " );
48
49 ????Data?d2;
50 ????Data::loadData(d2,? " output.txt " );
51
52 ???? // ?results?should?be?the?same.
53 ????ToolLib::LOG(TOSTR(d2.mInt));
54 }

?

成員serialize函數(shù)是定義類如何被串行化之規(guī)則的核心。
由于使用了RTTI機(jī)制,serialize函數(shù)不需要為virtual,永遠(yuǎn)只要是void就可以,在串行化指針的時(shí)候能夠被正確調(diào)用。
serialize函數(shù)中的 & 運(yùn)算符在load時(shí)調(diào)用 >>,而在save時(shí)調(diào)用 <<,這樣save和load只要一個(gè)函數(shù)就可以。
saveData和loadData函數(shù)必不可少,由于serialization庫強(qiáng)大的編譯檢查機(jī)制,如果不用這樣的方式來save一個(gè)對象,往往會因?yàn)檫@個(gè)對象不是const而編譯失敗。
所用的archive類型可以任選,如text或binary,上例中的typedef即是為了封裝這一變化

非侵入性

下面一例演示了串行化不可侵入的類型。這里用的是 WildMagicLib2.5中的 2-Vector

?

#include? < WildMagic2p5 / Include / WmlVector2.h >

class ?Data
{
????friend?
class ?boost::serialization::access;

protected :

????template
< class ?Archive >
????
void ?serialize(Archive? & ?ar,? const ?unsigned? int ? /* ?file_version? */ )
????
{
????????ar?
& ?mVec2d;
????}


public :

????Wml::Vector2d?mVec2d;

????
static ? void ?saveData( const ?Data & ?obj,?std:: string ?fileName);
????
static ? void ?loadData(Data & ?obj,?std:: string ?fileName);
}
;

namespace ?boost? {?
namespace ?serialization? {
????template
< class ?Archive,? class ?Real >
????
void ?serialize(Archive & ?ar,?Wml::Vector2 < Real >& ?g,? const ?unsigned? int ?version)
????
{
????????ar?
& ?g.X();
????????ar?
& ?g.Y();
????}

}
? // ?namespace?serialization
}
? // ?namespace?boost

?

這種情況下,需要這個(gè)全局serialize在能夠訪問到那個(gè)類里需要串行化的數(shù)據(jù),常常load和save的方法不一樣,如load時(shí)調(diào)用setVar,save時(shí)調(diào)用getVar,這時(shí)Archive::is_loading和Archive::is_saving常數(shù)就有用了。一種等價(jià)但是更直觀的方法是使用BOOST_SERIALIZATION_SPLIT_MEMBER或者BOOST_SERIALIZATION_SPLIT_FREE宏,兩者分別生成調(diào)用load/save成員函數(shù)和load/save全局函數(shù)的代碼。

在serialization內(nèi)部,是通過定義全局serialize函數(shù)模板,并在里面調(diào)用成員serialize函數(shù)來實(shí)現(xiàn)的,如下所示,需要非侵入的對象只要特化這個(gè)全局函數(shù)就可以了。

?

// ?default?implemenation?-?call?the?member?function?"serialize"
template < class ?Archive,? class ?T >
inline?
void ?serialize(
????Archive?
& ?ar,?T? & ?t,? const ?BOOST_PFTO?unsigned? int ?file_version
)
{
????access::serialize(ar,?t,?static_cast
< unsigned? int > (file_version));
}

?

STL容器支持

通過包含一些serialization提供的頭文件,對STL容器可以像普通變量一樣支持

?

// ?STL?support?headers
#include? < boost / serialization / vector.hpp >
#include?
< boost / serialization / string .hpp >

class ?Data
{
????friend?
class ?boost::serialization::access;

protected :

????template
< class ?Archive >
????
void ?serialize(Archive? & ?ar,? const ?unsigned? int ? /* ?file_version? */ )
????
{
????????ar?
& ?mStr;
????????ar?
& ?mVecInt;
????????ar?
& ?mVecStr;
????}


public :

????std::
string ?mStr;
????std::vector
< int > ?mVecInt;
????std::vector
< std:: string > ?mVecStr;

????
static ? void ?saveData( const ?Data & ?obj,?std:: string ?fileName);
????
static ? void ?loadData(Data & ?obj,?std:: string ?fileName);
}
;

?

指針與數(shù)組

?

class ?ClassA
{
public :
????
int ?mInt;
}
;

class ?Data
{
????friend?
class ?boost::serialization::access;

protected :

????template
< class ?Archive >
????
void ?serialize(Archive? & ?ar,? const ?unsigned? int ? /* ?file_version? */ )
????
{
????????ar?
& ?mPtrInt;
????????ar?
& ?mArrInt;
????????ar?
& ?mPtrData;
????????ar?
& ?mPtrA;
????}


public :

????Data():mPtrData(NULL),?mPtrInt(NULL),?mPtrA(NULL)
{}

????Data
* ?mPtrData;
????
int ?mArrInt[ 10 ];
????
int * ?mPtrInt;
????ClassA
* ?mPtrA;

????
static ? void ?saveData( const ?Data & ?obj,?std:: string ?fileName);
????
static ? void ?loadData(Data & ?obj,?std:: string ?fileName);
}
;

namespace ?boost? {?
namespace ?serialization? {
????template
< class ?Archive >
????
void ?serialize(Archive & ?ar,? int & ?g,? const ?unsigned? int ?version)
????
{
????????ar?
& ?g;
????}

}
? // ?namespace?serialization
}
? // ?namespace?boost

?

數(shù)組可以直接串行化,指針比須保證有效,所以必須保證在串行化之前經(jīng)過初始化。
對于基本類型如int,可以直接串行化,但其指針int*,要當(dāng)作不可侵入類型的指針來看待,所以需要一個(gè)全局serialize函數(shù)來說明int類型的串行化方式

對于有基類指針的串行化,代碼如下

?

class ?ClassA
{
public :
????
int ?mIntA;

????
virtual ? void ?someMethod()? = ?NULL;
????
????template
< class ?Archive >
????
void ?serialize(Archive? & ?ar,? const ?unsigned? int ? /* ?file_version? */ )
????
{
????????ar?
& ?mIntB;
????}

}
;

BOOST_IS_ABSTRACT(ClassA)

class ?ClassB:? public ?ClassA
{
public :
????
int ?mIntB;
????
????
virtual ? void ?someMethod() {}

????template
< class ?Archive >
????
void ?serialize(Archive? & ?ar,? const ?unsigned? int ? /* ?file_version? */ )
????
{
????????ar?
& ?boost::serialization::base_object < ClassA > ( * this );
????????ar?
& ?mIntB;
????}

}
;

BOOST_CLASS_EXPORT(ClassB)

?

純虛類后加上BOOST_ISABSTRACT,而可能會被串行化到的子類用BOOST_CLASS_EXPORT,這樣就可以在任何地方串行化 ClassA* 的成員變量。
子類的serialize函數(shù)里必須要照顧到基類的成員。

版本控制

在serialize函數(shù)中的version參數(shù)就是用于版本控制的,所有類的版本號默認(rèn)為0,新版本的類可以自己指定版本號以便與舊版本相區(qū)別。如下

BOOST_CLASS_VERSION(ClassA, 1)

對于save過程,版本號始終為新的,而load過程取決于文件中保存的值,對于新版本新增變量的情況可以這樣解決

?

// ?old?definition
class ?ClassA
{
public :
????
int ?mInt;
}
;

// ?new?definition
class ?ClassA
{
public :
????
int ?mInt;
????
int ?mIntNew;

????template
< class ?Archive >
????
void ?serialize(Archive? & ?ar,? const ?unsigned? int ?ver)
????
{
????????ar?
& ?mInt;

????????
if (ver? == ? 1 )
????????????ar?
& ?mIntB;
????}

}
;

BOOST_CLASS_VERSION(ClassA,?
1 )

?

對于有改動的情形,稍微復(fù)雜一點(diǎn),可以這樣

?

// ?old?definition
class ?ClassA
{
public :
????TypeA?mVarA;
}
;

// ?new?definition
class ?ClassA
{
public :

????
// ?suppose?now?we?use?B?and?C?instead?of?A
????TypeB?mVarB;
????TypeC?mVarC;

????template
< class ?Archive >
????
void ?serialize(Archive? & ?ar,? const ?unsigned? int ?ver)
????
{
????????
if (ver? < ? 1 )
????????
{
????????????
// ?here?must?be?loading

????????????TypeA?varA;
????????????ar?
& ?varA;
????????????
????????????
// ?now?derive?mVarB?&?mVarC?from?varA;
????????}

????????
else
????????
{
????????????ar?
& ?mVarB;
????????????ar?
& ?mVarC;
????????}

????}

}
;

BOOST_CLASS_VERSION(ClassA,?
1 )


?