在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

什么時(shí)候需要Boost序列化

科技綠洲 ? 來(lái)源:Linux開(kāi)發(fā)架構(gòu)之路 ? 作者:Linux開(kāi)發(fā)架構(gòu)之路 ? 2023-11-10 10:14 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

程序開(kāi)發(fā)中,序列化是經(jīng)常需要用到的。像一些相對(duì)高級(jí)語(yǔ)言,比如JAVA, C#都已經(jīng)很好的支持了序列化,那么C++呢?當(dāng)然一個(gè)比較好的選擇就是用Boost,這個(gè)號(hào)稱C++準(zhǔn)標(biāo)準(zhǔn)庫(kù)的東西。

什么時(shí)候需要序列化呢?舉個(gè)例子,我們定義了一個(gè)class,比如:

class CCar
{
public:
	void SetName(std::string& strName){m_strName = strName;}
	std::string GetName() const{return m_strName;}
private:
	std::string m_strName;
};

然后我們想把這個(gè)類的一個(gè)對(duì)象保存到文件中或者通過(guò)網(wǎng)絡(luò)發(fā)出去,怎么辦呢?答案就是:把這個(gè)對(duì)象序列化,然后我們可以得到一個(gè)二進(jìn)制字節(jié)流,或者XML格式表示等等。

這樣我們就可以保存這個(gè)對(duì)象到文件中或者通過(guò)網(wǎng)絡(luò)發(fā)出去了。把序列化的數(shù)據(jù)進(jìn)行反序列化,就可以得到一個(gè)CCar對(duì)象了。

Boost已經(jīng)很好的支持了序列化這個(gè)東西,很好很強(qiáng)大。

Boost網(wǎng)站上有介紹: Serialization

對(duì)于序列化,Boost是這么定義的:

Here, we use the term "serialization" to mean the reversible deconstruction of an arbitrary set of C++ data structures to a sequence of bytes. Such a system can be used to reconstitute an equivalent structure in another program context. Depending on the context, this might used implement object persistence, remote parameter passing or other facility. In this system we use the term"archive" to refer to a specific rendering of this stream of bytes. This could be a file of binary data, text data, XML, or some other created by the user of this library.

這段英文很簡(jiǎn)單,我相信大多數(shù)程序員都能看的懂。

基本上Boost序列化可以分為兩種模式:侵入式(intrusive)和非侵入式(non-intrusive)

侵入式(intrusive)

先來(lái)看看侵入式。我們先來(lái)定義一個(gè)類,這個(gè)類支持序列化:

class CMyData
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		ar & _tag;
		ar & _text;
	}

	
public:
	CMyData():_tag(0), _text(""){}

	CMyData(int tag, std::string text):_tag(tag), _text(text){}

	int GetTag() const {return _tag;}
	std::string GetText() const {return _text;}

private:
	int _tag;
	std::string _text;
};

其中,我們可以看到這些代碼:

friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		ar & _tag;
		ar & _text;
	}

這些代碼就是用來(lái)實(shí)現(xiàn)序列化的,這些代碼存在于類CMyData中,也就是為什么稱這種模式是“侵入式”的原因了。

看看怎么把這個(gè)對(duì)象序列化。這里,我把這個(gè)對(duì)象以二進(jìn)制的方式保存到了一個(gè)ostringstream中了,當(dāng)然也可以保存為其他形式,比如XML。也可以保存到文件中。代碼都是類似的。

void TestArchive1()
{
	CMyData d1(2012, "China, good luck");
	std::ostringstream os;
	boost::archive::binary_oarchive oa(os);
	oa < < d1;//序列化到一個(gè)ostringstream里面

	std::string content = os.str();//content保存了序列化后的數(shù)據(jù)。

	CMyData d2;
	std::istringstream is(content);
	boost::archive::binary_iarchive ia(is);
	ia > > d2;//從一個(gè)保存序列化數(shù)據(jù)的string里面反序列化,從而得到原來(lái)的對(duì)象。

	std::cout < < "CMyData tag: " < < d2.GetTag() < < ", text: " < < d2.GetText() < < "n";
}

先生成一個(gè)CMyData的對(duì)象,然后序列化保存到一個(gè)ostringstream中,接著再把這個(gè)序列化的數(shù)據(jù)反序列化,得到原來(lái)的對(duì)象,打印出來(lái),我們會(huì)發(fā)現(xiàn)反序列化的對(duì)象的數(shù)據(jù)成員跟序列化前的對(duì)象一模一樣。哈哈,成功了,簡(jiǎn)單吧。至于Boost怎么實(shí)現(xiàn)這個(gè)過(guò)程的,看Boost源代碼吧,Boost的網(wǎng)站上也有一些介紹。Boost確實(shí)設(shè)計(jì)的很巧妙,不得不佩服那幫家伙。

那么可以序列化CMyData的子類嗎,答案是肯定的。其實(shí)很簡(jiǎn)單就是在子類的序列化函數(shù)里面先序列化基類的??纯创a就明白了:

class CMyData_Child: public CMyData
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		// serialize base class information
		ar & boost::serialization::base_object< CMyData >(*this);
		ar & _number;
	}


public:
	CMyData_Child():_number(0.0){}

	CMyData_Child(int tag, std::string text, float number):CMyData(tag, text), _number(number){}

	float GetNumber() const{return _number;}

private:
	float _number;
};

void TestArchive3()
{
	CMyData_Child d1(2012, "China, good luck", 1.2);
	std::ostringstream os;
	boost::archive::binary_oarchive oa(os);
	oa < < d1;//序列化到一個(gè)ostringstream里面

	std::string content = os.str();//content保存了序列化后的數(shù)據(jù)。

	CMyData_Child d2;
	std::istringstream is(content);
	boost::archive::binary_iarchive ia(is);
	ia > > d2;//從一個(gè)保存序列化數(shù)據(jù)的string里面反序列化,從而得到原來(lái)的對(duì)象。

	std::cout < < "CMyData_Child tag: " < < d2.GetTag() < < ", text: " < < d2.GetText() < < ", number: "<

非侵入式(non-intrusive)

侵入式的缺點(diǎn)就是需要在class里面加一些代碼,那么有時(shí)候可能這個(gè)class已經(jīng)存在了,或者我們并不想往里面加入這么些代碼,那么怎么辦呢?ok,輪到非侵入式出場(chǎng)了。

比方說(shuō)我們有這么個(gè)類:

class CMyData2
{
public:
	CMyData2():_tag(0), _text(""){}

	CMyData2(int tag, std::string text):_tag(tag), _text(text){}

	int _tag;
	std::string _text;
};

那么我們可以這么序列化:

namespace boost {
	namespace serialization {

		template< class Archive >
		void serialize(Archive & ar, CMyData2 & d, const unsigned int version)
		{
			ar & d._tag;
			ar & d._text;
		}

	} // namespace serialization
} // namespace boost

然后調(diào)用還是跟侵入式一模一樣,看:

void TestArchive2()
{
	CMyData2 d1(2012, "China, good luck");
	std::ostringstream os;
	boost::archive::binary_oarchive oa(os);
	oa < < d1;//序列化到一個(gè)ostringstream里面

	std::string content = os.str();//content保存了序列化后的數(shù)據(jù)。

	CMyData2 d2;
	std::istringstream is(content);
	boost::archive::binary_iarchive ia(is);
	ia > > d2;//從一個(gè)保存序列化數(shù)據(jù)的string里面反序列化,從而得到原來(lái)的對(duì)象。

	std::cout < < "CMyData2 tag: " < < d2._tag < < ", text: " < < d2._text < < "n";
}

成功。跟侵入式相比,非侵入式省去了在具體類里面加入序列化代碼。但是我們看看非侵入式模式里面的類的定義,我們會(huì)發(fā)現(xiàn)我們把數(shù)據(jù)成員搞成public的了。這是為什么呢?看看這個(gè)就明白了:

template< class Archive >
		void serialize(Archive & ar, CMyData2 & d, const unsigned int version)
		{
			ar & d._tag;
			ar & d._text;
		}

原來(lái)序列化函數(shù)需要訪問(wèn)數(shù)據(jù)成員。這就是非侵入式的一個(gè)缺點(diǎn)了:需要把數(shù)據(jù)成員暴露出來(lái)。通過(guò)直接訪問(wèn)數(shù)據(jù)成員也好,通過(guò)函數(shù)訪問(wèn)也好,總之需要這個(gè)類把數(shù)據(jù)成員暴露出來(lái),這樣序列化函數(shù)才能訪問(wèn)。世界上沒(méi)有十全十美的東西,有時(shí)我們得到一個(gè)東西,往往會(huì)失去另外一個(gè)東西,不是嗎?

侵入式和非侵入式各有各的用處,看具體情況來(lái)決定用哪個(gè)了。

非侵入式可以支持子類序列化嗎?可以。跟侵入式一樣,其實(shí)也就是先序列化一下基類,然后再序列化子類的數(shù)據(jù)成員??创a:

class CMyData2_Child: public CMyData2
{
public:
	CMyData2_Child():_number(0.0){}

	CMyData2_Child(int tag, std::string text, float number):CMyData2(tag, text), _number(number){}

	float _number;
};

namespace boost {
	namespace serialization {

		template< class Archive >
		void serialize(Archive & ar, CMyData2_Child & d, const unsigned int version)
		{
			// serialize base class information
			ar & boost::serialization::base_object< CMyData2 >(d);
			ar & d._number;
		}

	} // namespace serialization
} // namespace boost

void TestArchive4()
{
	CMyData2_Child d1(2012, "test non-intrusive child class", 5.6);
	std::ostringstream os;
	boost::archive::binary_oarchive oa(os);
	oa < < d1;//序列化到一個(gè)ostringstream里面

	std::string content = os.str();//content保存了序列化后的數(shù)據(jù)。

	CMyData2_Child d2;
	std::istringstream is(content);
	boost::archive::binary_iarchive ia(is);
	ia > > d2;//從一個(gè)保存序列化數(shù)據(jù)的string里面反序列化,從而得到原來(lái)的對(duì)象。

	std::cout < < "CMyData2_Child tag: " < < d2._tag < < ", text: " < < d2._text < < ", number: "<

好了,以上就是序列化的簡(jiǎn)單用法。接下里我們來(lái)重點(diǎn)關(guān)注一下數(shù)據(jù)成員的序列化,假如我們的類里面有指針,那么還能序列化嗎?比如下面的代碼,會(huì)發(fā)生什么事?

序列化指針數(shù)據(jù)成員

class CMyData
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		ar & _tag;
		ar & _text;
	}


public:
	CMyData():_tag(0), _text(""){}

	CMyData(int tag, std::string text):_tag(tag), _text(text){}

	int GetTag() const {return _tag;}
	std::string GetText() const {return _text;}

private:
	int _tag;
	std::string _text;
};
class CMyData_Child: public CMyData
{
private:
	friend class boost::serialization::access;

	template




	void serialize(Archive& ar, const unsigned int version)
	{
		// serialize base class information
		ar & boost::serialization::base_object



    (*this);
		ar & _number;
	}


public:
	CMyData_Child():_number(0.0){}

	CMyData_Child(int tag, std::string text, float number):CMyData(tag, text), _number(number){}

	float GetNumber() const{return _number;}

private:
	float _number;
};
class CMyData_Container
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		for(int i = 0; i < 3; i++)
		{
			ar & pointers[i];
		}
	}
public:
	CMyData* pointers[3];
};

void TestPointerArchive()
{
	std::string content;
	{
		CMyData d1(1, "a");
		CMyData_Child d2(2, "b", 1.5);

		CMyData_Container containter;
		containter.pointers[0] = &d1;
		containter.pointers[1] = &d2;
		containter.pointers[2] = &d1;

		std::ostringstream os;
		boost::archive::binary_oarchive oa(os);
		oa < < containter;

		content = os.str();
	}

	//反序列化
	{
		CMyData_Container container;
		std::istringstream is(content);
		boost::archive::binary_iarchive ia(is);
		ia > > container;

		for (int i = 0; i < 3; i++)
		{
			CMyData* d = container.pointers[i];
			std::cout < < "pointer" < < i + 1 < ": " < < d- >GetText() < < "n";

			if (i == 1)
			{
				CMyData_Child* child = reinterpret_cast< CMyData_Child* >(d);
				std::cout < < "pointer" < < i + 1 < ", number: " < < child- >GetNumber() < < "n";
			}
		}
	}
}

注意,我們?cè)贑MyData_Container對(duì)象里面放進(jìn)去了3個(gè)指針,其中第二個(gè)指針是CMyData的子類。

然后進(jìn)行序列化,再反序列化,我們會(huì)發(fā)現(xiàn),第一個(gè),第三個(gè)指針輸出了正確的信息,然而第二個(gè)指針有點(diǎn)問(wèn)題,本身我們存進(jìn)去的時(shí)候是個(gè)CMyData_Child 對(duì)象,通過(guò)測(cè)試我們可以發(fā)現(xiàn),CMyData_Child的基類部分,我們可以正確的輸出,但是CMyData_Child的成員_number,卻得不到正確信息。這是個(gè)問(wèn)題。

也就是說(shuō),序列化指針是可以的,但是需要注意多態(tài)的問(wèn)題。假如我們不需要考慮多態(tài),那么以上的代碼就可以正常工作了。但是如果要考慮多態(tài)的問(wèn)題,那么就得特殊處理了。下面再來(lái)介紹序列化多態(tài)指針。

序列化多態(tài)指針數(shù)據(jù)成員

上一個(gè)章節(jié)里面演示了如果序列化指針成員,但是有個(gè)問(wèn)題,就是當(dāng)基類指針指向一個(gè)派生類對(duì)象的時(shí)候,然后序列化這個(gè)指針,那么派生類的信息就被丟掉了。這個(gè)很不好。那么怎么來(lái)解決這個(gè)問(wèn)題呢?很幸運(yùn),Boost的開(kāi)發(fā)人員已經(jīng)考慮到了這個(gè)問(wèn)題。再一次感受到Boost的強(qiáng)大。

有兩種方法可以解決這個(gè)問(wèn)題:

  1. registration
  2. export

具體可以參考: http://www.boost.org/doc/libs/1_51_0/libs/serialization/doc/serialization.html#derivedpointers

這里我們介紹第二種方式,這種方式比較簡(jiǎn)單,也用的比較好。就是通過(guò)一個(gè)宏把派生類給命名一下。

這個(gè)關(guān)鍵的宏是:BOOST_CLASS_EXPORT_GUID

相關(guān)解釋:

The macro BOOST_CLASS_EXPORT_GUID associates a string literal with a class. In the above example we've used a string rendering of the class name. If a object of such an "exported" class is serialized through a pointer and is otherwise unregistered, the "export" string is included in the archive. When the archive is later read, the string literal is used to find the class which should be created by the serialization library. This permits each class to be in a separate header file along with its string identifier. There is no need to maintain a separate "pre-registration" of derived classes that might be serialized. This method of registration is referred to as "key export".

如何使用這個(gè)神奇的宏BOOST_CLASS_EXPORT_GUID來(lái)實(shí)現(xiàn)序列化指向派生類的指針呢?先給出代碼:

class CMyData
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		ar & _tag;
		ar & _text;
	}

	
public:
	CMyData():_tag(0), _text(""){}

	CMyData(int tag, std::string text):_tag(tag), _text(text){}
	virtual ~CMyData(){}

	int GetTag() const {return _tag;}
	std::string GetText() const {return _text;}

private:
	int _tag;
	std::string _text;
};

class CMyData_Child: public CMyData
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		// serialize base class information
		ar & boost::serialization::base_object< CMyData >(*this);
		ar & _number;
	}


public:
	CMyData_Child():_number(0.0){}

	CMyData_Child(int tag, std::string text, float number):CMyData(tag, text), _number(number){}

	float GetNumber() const{return _number;}

private:
	float _number;
};

BOOST_CLASS_EXPORT_GUID(CMyData_Child, "CMyData_Child")

class CMyData_Container
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		for(int i = 0; i < 3; i++)
		{
			ar & pointers[i];
		}
	}
public:
	CMyData* pointers[3];
};


void TestPointerArchive()
{
	std::string content;
	{
		CMyData d1(1, "a");
		CMyData_Child d2(2, "b", 1.5);

		CMyData_Container containter;
		containter.pointers[0] = &d1;
		containter.pointers[1] = &d2;
		containter.pointers[2] = &d1;

		std::ostringstream os;
		boost::archive::binary_oarchive oa(os);
		oa < < containter;

		content = os.str();
	}

	//·′DòáD?ˉ
	{
		CMyData_Container container;
		std::istringstream is(content);
		boost::archive::binary_iarchive ia(is);
		ia > > container;

		for (int i = 0; i < 3; i++)
		{
			CMyData* d = container.pointers[i];
			std::cout < < "pointer" < < i + 1 < ": " < < d- >GetText() < < "n";

			if (i == 1)
			{
				CMyData_Child* child = reinterpret_cast< CMyData_Child* >(d);
				std::cout < < "pointer" < < i + 1 < ", number: " < < child- >GetNumber() < < "n";
			}
		}
	}
}

這次我們可以正確的讀取到第二個(gè)指針指向的對(duì)象了,可以看到_number的爭(zhēng)取值了。

把代碼和上個(gè)版本想比較,我們會(huì)發(fā)現(xiàn)2個(gè)不同:

  1. CMyData類里面多了個(gè)虛的析構(gòu)函數(shù);
  2. 調(diào)用BOOST_CLASS_EXPORT_GUID給派生類CMyData_Child綁定一個(gè)字符串。

第二點(diǎn)很容易理解,就是給某個(gè)派生類命名一下,這樣就可以當(dāng)作一個(gè)key來(lái)找到相應(yīng)的類。那么第一點(diǎn)為什么要增加一個(gè)虛析構(gòu)函數(shù)呢?是我無(wú)意中添加的嗎?當(dāng)然不是,其實(shí)這個(gè)是序列化指向派生類的指針的其中一個(gè)關(guān)鍵。先看Boost網(wǎng)站上面的一段描述:

It turns out that the kind of object serialized depends upon whether the base class (base in this case) is polymophic or not. Ifbase is not polymorphic, that is if it has no virtual functions, then an object of the typebasewill be serialized. Information in any derived classes will be lost. If this is what is desired (it usually isn't) then no other effort is required.

If the base class is polymorphic, an object of the most derived type (derived_oneorderived_twoin this case) will be serialized. The question of which type of object is to be serialized is (almost) automatically handled by the library.

ok,通過(guò)這段描述,我們發(fā)現(xiàn)Boost序列化庫(kù)會(huì)判斷基類是不是多態(tài)的。判斷的依據(jù)就是這個(gè)基類里面有沒(méi)有虛函數(shù)。我們知道,當(dāng)一個(gè)類里面有虛函數(shù)的時(shí)候,C++編譯器會(huì)自動(dòng)給這個(gè)類增加一個(gè)成員:_vfptr,就是虛函數(shù)表指針。我沒(méi)有花太多時(shí)間去看Boost有關(guān)這部分的源代碼,但是我猜測(cè)Boost是根據(jù)這個(gè)_vfptr來(lái)判斷是需要序列化基類,還是派生類的。我們?cè)黾右粋€(gè)虛析構(gòu)函數(shù)的目的也就是讓CMyData產(chǎn)生一個(gè)_vfptr。我們可以試一下把上面的代碼里面的析構(gòu)函數(shù)改成非虛的,那么派生類序列化就會(huì)失敗,跟上一個(gè)章節(jié)得到相同的結(jié)果。至于Boost怎么知道該序列化哪個(gè)派生類,相信這個(gè)是BOOST_CLASS_EXPORT_GUID的功勞,至于怎么實(shí)現(xiàn),還是需要看源代碼,但是我自己沒(méi)有仔細(xì)研究過(guò),有興趣的朋友可以學(xué)習(xí)Boost的源代碼。Boost的設(shè)計(jì)很巧妙,我們可以學(xué)到不少東西。當(dāng)然這個(gè)得有時(shí)間細(xì)細(xì)學(xué)習(xí)。好了,序列化指向派生類指針就2個(gè)要點(diǎn):

  1. 讓Boost知道基類是多態(tài)的,其實(shí)就是確保基類里面有個(gè)虛函數(shù);
  2. 通過(guò)BOOST_CLASS_EXPORT_GUID給派生類綁定一個(gè)字符串,當(dāng)作一個(gè)key。

至于第一種序列化指向派生類的基類指針:registration,可以參考http://www.boost.org/doc/libs/1_51_0/libs/serialization/doc/serialization.html#derivedpointers,上面講的非常清楚。我本人很少使用這種方式,這里也就略過(guò)不講了。

序列化數(shù)組

一個(gè)小細(xì)節(jié),上面講到的序列化指針章節(jié)里面,我們看到代碼:

class CMyData_Container
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		for(int i = 0; i < 3; i++)
		{
			ar & pointers[i];
		}
	}
public:
	CMyData* pointers[3];
};

其中的序列化函數(shù)里面有個(gè)for循環(huán),難道每次序列化一個(gè)數(shù)組都需要弄一個(gè)for語(yǔ)句嗎,這個(gè)是不是可以改進(jìn)呢?答案是肯定的。Boost自己會(huì)檢測(cè)數(shù)組。也就是說(shuō)我們可以把代碼改成下面的形式:

class CMyData_Container
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		ar & pointers;
	}
public:
	CMyData* pointers[3];
};

代碼短了很多,方便吧。

支持STL容器

上面我們使用了一個(gè)普通數(shù)組來(lái)保存指針,我相信在平常寫(xiě)程序過(guò)程中,大家都會(huì)使用STL容器,比如list,map,array等等。至少我自己是經(jīng)常使用的。那么Boost序列化庫(kù)可以序列化STL容器嗎?很幸運(yùn),Boost序列化庫(kù)已經(jīng)支持了STL容器。原話是:

The above example uses an array of members. More likely such an application would use an STL collection for such a purpose. The serialization library contains code for serialization of all STL classes. Hence, the reformulation below will also work as one would expect.

我們一開(kāi)始就是用std::string作為CMyData的一個(gè)成員,我們不需要做任何工作就可以直接序列化std::string,這是因?yàn)锽oost序列化庫(kù)已經(jīng)支持std::string了。從上面的英文描述里面可以看到Boost serialization庫(kù)可以支持所有STL類,神奇吧。至少我本人經(jīng)常使用std::list, vector, map, string等,都可以正常工作。下面的代碼使用std::vector代替了普通數(shù)組,可以正常工作。

class CMyData
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		ar & _tag;
		ar & _text;
	}

	
public:
	CMyData():_tag(0), _text(""){}

	CMyData(int tag, std::string text):_tag(tag), _text(text){}
	virtual ~CMyData(){}

	int GetTag() const {return _tag;}
	std::string GetText() const {return _text;}

private:
	int _tag;
	std::string _text;
};

class CMyData_Child: public CMyData
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		// serialize base class information
		ar & boost::serialization::base_object< CMyData >(*this);
		ar & _number;
	}


public:
	CMyData_Child():_number(0.0){}

	CMyData_Child(int tag, std::string text, float number):CMyData(tag, text), _number(number){}

	float GetNumber() const{return _number;}

private:
	float _number;
};

BOOST_CLASS_EXPORT_GUID(CMyData_Child, "CMyData_Child")

//ê1ó?STLèY?÷
class CMyData_ContainerSTL
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		ar & vPointers;
	}
public:
	std::vector< CMyData* > vPointers;
};



void TestPointerArchiveWithSTLCollections()
{
	std::string content;
	{
		CMyData d1(1, "parent obj");
		CMyData_Child d2(2, "child obj", 2.5);

		CMyData_ContainerSTL containter;
		containter.vPointers.push_back(&d1);
		containter.vPointers.push_back(&d2);
		containter.vPointers.push_back(&d1);
		

		std::ostringstream os;
		boost::archive::binary_oarchive oa(os);
		oa < < containter;

		content = os.str();
	}

	//·′DòáD?ˉ
	{
		CMyData_ContainerSTL container;
		std::istringstream is(content);
		boost::archive::binary_iarchive ia(is);
		ia > > container;

		std::cout< "Test STL collections:n";
		BOOST_FOREACH(CMyData* p, container.vPointers)
		{
			std::cout < < "object text: " < < p- >GetText() < < "n";

			CMyData_Child* child = dynamic_cast< CMyData_Child* >(p);
			if (child)
			{
				std::cout < < "child object number: " < < child- >GetNumber() < < "n";
			}
		}
	}
}

一不小心就用到了BOOST_FOREACH,看來(lái)這個(gè)確實(shí)很好用啊,呵呵。省去了寫(xiě)很長(zhǎng)的iterator來(lái)遍歷整個(gè)vector。

class版本

再來(lái)考慮一個(gè)問(wèn)題,比方說(shuō)現(xiàn)在我們程序升級(jí)了,然后把某個(gè)類給升級(jí)了一下,加了一個(gè)成員,那么之前保存的序列化的數(shù)據(jù)還能匹配到新的類嗎?看一下序列化函數(shù),我們會(huì)發(fā)現(xiàn)這個(gè)序列化函數(shù)有個(gè)參數(shù),叫做version

template

void serialize(Archive& ar, const unsigned int version)

通過(guò)這個(gè)參數(shù),我們就可以解決class版本的問(wèn)題??催@段描述

In general, the serialization library stores a version number in the archive for each class serialized. By default this version number is 0. When the archive is loaded, the version number under which it was saved is read.

也就是說(shuō)如果我們不刻意指定version,那么Boost序列化庫(kù)就會(huì)默認(rèn)設(shè)置為0并且保存到序列化結(jié)果中。

如果我們要標(biāo)記不同的class版本,可以使用宏BOOST_CLASS_VERSION,比如

BOOST_CLASS_VERSION(CMyData, 1)

具體這里就不舉例了。參考Boost說(shuō)明。

save和load分開(kāi)

一直到現(xiàn)在我們都是用了一個(gè)序列化函數(shù)

template

void serialize(Archive& ar, const unsigned int version)

其實(shí),序列化包括序列化和發(fā)序列化兩部分,或者稱之為save和load,甚至mashalling,unmarshalling。反正就這個(gè)意思。

還有一個(gè)奇怪的地方,就是通常我們輸入輸出是用<<和>>的,那么在函數(shù)serialize里面我們用了&。其實(shí)這個(gè)是Boost對(duì)&做了一個(gè)封裝。假如現(xiàn)在是做序列化,那么&就等同于<<,假如是反序列化,那么&就等同于>>。然后序列化和反序列化統(tǒng)統(tǒng)用一個(gè)函數(shù)serialize來(lái)實(shí)現(xiàn)。這也體現(xiàn)了Boost的巧妙設(shè)計(jì)。

那么如果有特殊需求,我們需要把序列化和反序列化分開(kāi),應(yīng)該怎么實(shí)現(xiàn)呢?

就好比上面的class版本問(wèn)題,save和load可能就是不一樣的,因?yàn)閘oad需要考慮兼容舊的版本。這里就偷懶使用Boost文檔上的例子了。我們可以看到save和load是分開(kāi)的。

#include 
#include 
#include 
#include 

class bus_route
{
    friend class boost::serialization::access;
    std::list

注意需要使用宏BOOST_SERIALIZATION_SPLIT_MEMBER()來(lái)告訴Boost序列化庫(kù)使用save和load代替serialize函數(shù)。

到這里,我們幾乎把Boost序列化庫(kù)所有的內(nèi)容都介紹完畢了。這個(gè)庫(kù)是相當(dāng)?shù)膎ice,基本可以cover所有的case。而且就開(kāi)源庫(kù)來(lái)講,Boost的說(shuō)明文檔真的算是很好的了。基本上都有詳細(xì)的說(shuō)明,就序列化庫(kù)而言,直接看這個(gè)頁(yè)面就基本ok了,Serialization - Tutorial 相當(dāng)?shù)脑敿?xì)。盡管讀英文比較累,但是可以獲得原汁原味的第一手權(quán)威資料,花這些功夫還是值得的。

我的例子里面使用了二進(jìn)制流來(lái)保存序列化后的數(shù)據(jù),其實(shí)還有其他的archive格式,比如text,XML等等。甚至我們可以自己來(lái)實(shí)現(xiàn)序列化格式。Boost已經(jīng)定義了一個(gè)統(tǒng)一的接口,我們要實(shí)現(xiàn)自己的格式,只需要繼承相應(yīng)的Boost::archive里面的類就可以了。

好了,寫(xiě)完了,希望對(duì)大家有點(diǎn)幫助。如有錯(cuò)誤,歡迎指出。

附,完整測(cè)試代碼,使用這段代碼前需要確保VISUAL STUDIO已經(jīng)設(shè)置了Boost的路徑。

// Serialization.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include "boost/serialization/serialization.hpp"
#include "boost/archive/binary_oarchive.hpp"
#include "boost/archive/binary_iarchive.hpp"
#include 
#include "boost/foreach.hpp"
#include "boost/any.hpp"
#include 



#include < string >
#include < Windows.h >
#include < iostream >
#include < sstream >
#include < vector >


//測(cè)試序列化
class CMyData
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		ar & _tag;
		ar & _text;
	}

	
public:
	CMyData():_tag(0), _text(""){}

	CMyData(int tag, std::string text):_tag(tag), _text(text){}
	virtual ~CMyData(){}

	int GetTag() const {return _tag;}
	std::string GetText() const {return _text;}

private:
	int _tag;
	std::string _text;
};


void TestArchive1()
{
	std::string content;

	{
		CMyData d1(2012, "China, good luck");
		std::ostringstream os;
		boost::archive::binary_oarchive oa(os);
		oa < < d1;//序列化到一個(gè)ostringstream里面

		content = os.str();//content保存了序列化后的數(shù)據(jù)。
	}
	

	{
		CMyData d2;
		std::istringstream is(content);
		boost::archive::binary_iarchive ia(is);
		ia > > d2;//從一個(gè)保存序列化數(shù)據(jù)的string里面反序列化,從而得到原來(lái)的對(duì)象。

		std::cout < < "CMyData tag: " < < d2.GetTag() < < ", text: " < < d2.GetText() < < "n";
	}
	
}


class CMyData2
{
public:
	CMyData2():_tag(0), _text(""){}

	CMyData2(int tag, std::string text):_tag(tag), _text(text){}

	int _tag;
	std::string _text;
};

namespace boost {
	namespace serialization {

		template< class Archive >
		void serialize(Archive & ar, CMyData2 & d, const unsigned int version)
		{
			ar & d._tag;
			ar & d._text;
		}

	} // namespace serialization
} // namespace boost

void TestArchive2()
{
	CMyData2 d1(2012, "China, good luck");
	std::ostringstream os;
	boost::archive::binary_oarchive oa(os);
	oa < < d1;//序列化到一個(gè)ostringstream里面

	std::string content = os.str();//content保存了序列化后的數(shù)據(jù)。

	CMyData2 d2;
	std::istringstream is(content);
	boost::archive::binary_iarchive ia(is);
	ia > > d2;//從一個(gè)保存序列化數(shù)據(jù)的string里面反序列化,從而得到原來(lái)的對(duì)象。

	std::cout < < "CMyData2 tag: " < < d2._tag < < ", text: " < < d2._text < < "n";
}


//序列化子類,侵入式
class CMyData_Child: public CMyData
{
private:
	friend class boost::serialization::access;

	template< class Archive >
	void serialize(Archive& ar, const unsigned int version)
	{
		// serialize base class information
		ar & boost::serialization::base_object< CMyData >(*this);
		ar & _number;
	}


public:
	CMyData_Child():_number(0.0){}

	CMyData_Child(int tag, std::string text, float number):CMyData(tag, text), _number(number){}

	float GetNumber() const{return _number;}

private:
	float _number;
};

BOOST_CLASS_EXPORT_GUID(CMyData_Child, "CMyData_Child")


void TestArchive3()
{
	CMyData_Child d1(2012, "China, good luck", 1.2);
	std::ostringstream os;
	boost::archive::binary_oarchive oa(os);
	oa < < d1;//序列化到一個(gè)ostringstream里面

	std::string content = os.str();//content保存了序列化后的數(shù)據(jù)。

	CMyData_Child d2;
	std::istringstream is(content);
	boost::archive::binary_iarchive ia(is);
	ia > > d2;//從一個(gè)保存序列化數(shù)據(jù)的string里面反序列化,從而得到原來(lái)的對(duì)象。

	std::cout < < "CMyData_Child tag: " < < d2.GetTag() < < ", text: " < < d2.GetText() < < ", number: "<
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    2988

    瀏覽量

    109026
  • Boost
    +關(guān)注

    關(guān)注

    5

    文章

    385

    瀏覽量

    49598
  • 程序
    +關(guān)注

    關(guān)注

    117

    文章

    3826

    瀏覽量

    82813
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2119

    瀏覽量

    75148
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    如何使用Serde進(jìn)行序列化和反序列化

    。它是 Rust 生態(tài)中最受歡迎的序列化庫(kù)之一。 基礎(chǔ)用法 安裝 在 Rust 項(xiàng)目中使用 Serde,需要在 Cargo.toml 文件中添加如下依賴: [dependencies] serde
    的頭像 發(fā)表于 09-30 17:09 ?1668次閱讀

    Java序列化的機(jī)制和原理

    本文講解了Java序列化的機(jī)制和原理。從文中你可以了解如何序列化一個(gè)對(duì)象,什么時(shí)候需要序列化以及Java
    發(fā)表于 07-10 07:27

    c語(yǔ)言序列化和反序列化有何區(qū)別

    這里寫(xiě)自定義目錄標(biāo)題c語(yǔ)言序列化和反序列化tplut.htplut.c測(cè)試代碼參考c語(yǔ)言序列化和反序列化網(wǎng)絡(luò)調(diào)用,數(shù)據(jù)傳輸都需要把數(shù)據(jù)
    發(fā)表于 07-14 07:32

    關(guān)于c語(yǔ)言序列化和反序列化的知識(shí)點(diǎn)看完你就懂了

    關(guān)于c語(yǔ)言序列和反序列化的知識(shí)點(diǎn)你就懂了
    發(fā)表于 10-15 08:47

    SpringMVC JSON框架的自定義序列化與反序列化

    限于createTime和updateTime,更貼近于需求缺點(diǎn)就是需要轉(zhuǎn)換的字段都需要使用注解,工作量有點(diǎn)大當(dāng)然有其他的統(tǒng)一處理方案,這里不贅述。自定義反序列化在jackson框架上實(shí)現(xiàn)自定義
    發(fā)表于 10-10 16:02

    理解PHP反序列化漏洞

    理解PHP反序列化漏洞
    發(fā)表于 09-07 11:03 ?7次下載
    理解PHP反<b class='flag-5'>序列化</b>漏洞

    java序列化和反序列化范例和JDK類庫(kù)中的序列化API

    存放在一個(gè)文件中; 2) 在網(wǎng)絡(luò)上傳送對(duì)象的字節(jié)序列。 在很多應(yīng)用中,需要對(duì)某些對(duì)象進(jìn)行序列化,讓它們離開(kāi)內(nèi)存空間,入住物理硬盤(pán),以便長(zhǎng)期保存。比如最常見(jiàn)的是Web服務(wù)器中的Session對(duì)象,當(dāng)有 10萬(wàn)用戶并發(fā)訪問(wèn),就有可能
    發(fā)表于 09-27 10:13 ?6次下載

    java序列化的幾種方式

    一.Java序列化的作用 有的時(shí)候我們想要把一個(gè)Java對(duì)象變成字節(jié)流的形式傳出去,有的時(shí)候我們想要從一個(gè)字節(jié)流中恢復(fù)一個(gè)Java對(duì)象。例如,有的時(shí)候我們想要 把一個(gè)Java對(duì)象寫(xiě)入到
    發(fā)表于 09-27 11:15 ?0次下載

    static屬性為什么不會(huì)被序列化

    實(shí)現(xiàn)序列化和反序列化為什么要實(shí)現(xiàn)Serializable接口?
    的頭像 發(fā)表于 07-15 11:03 ?2029次閱讀

    C#實(shí)現(xiàn)對(duì)象序列化的三種方式是什么

    很多小伙伴一提到序列化,都會(huì)想到二進(jìn)制序列化,但其實(shí)序列化并不僅僅只是二進(jìn)制序列化,我們常說(shuō)的對(duì)象序列化有三種方式,分別是二進(jìn)制
    的頭像 發(fā)表于 02-22 16:11 ?1473次閱讀
    C#實(shí)現(xiàn)對(duì)象<b class='flag-5'>序列化</b>的三種方式是什么

    python序列化對(duì)象

    序列化對(duì)象:將對(duì)象轉(zhuǎn)換為可以存儲(chǔ)或傳輸?shù)男问健? (1) 用于存儲(chǔ):將對(duì)象的字節(jié)序列存儲(chǔ)到文件中,程序退出后不會(huì)消失,便于后續(xù)使用。
    的頭像 發(fā)表于 03-10 09:57 ?2520次閱讀

    什么是序列化 為什么要序列化

    什么是序列化? “序列化”(Serialization )的意思是將一個(gè)對(duì)象轉(zhuǎn)化為字節(jié)流。 這里說(shuō)的對(duì)象可以理解為“面向?qū)ο蟆崩锏哪莻€(gè)對(duì)象,具體的就是存儲(chǔ)在內(nèi)存中的對(duì)象數(shù)據(jù)。 與之相反的過(guò)程是“反序列化
    的頭像 發(fā)表于 09-14 17:22 ?3266次閱讀
    什么是<b class='flag-5'>序列化</b> 為什么要<b class='flag-5'>序列化</b>

    ROS中的序列化實(shí)現(xiàn)

    不是很多。 為什么ROS不使用現(xiàn)成的序列化工具或者庫(kù)呢?可能ROS誕生的時(shí)候(2007年),有些序列化庫(kù)可能還不存在(protobuf誕生于2008年),更有可能是ROS的創(chuàng)造者認(rèn)為當(dāng)時(shí)沒(méi)有合適的工具
    的頭像 發(fā)表于 09-14 17:26 ?1168次閱讀

    如何用C語(yǔ)言進(jìn)行json的序列化和反序列化

    json是目前最為流行的文本數(shù)據(jù)傳輸格式,特別是在網(wǎng)絡(luò)通信上廣泛應(yīng)用,隨著物聯(lián)網(wǎng)的興起,在嵌入式設(shè)備上,也需要開(kāi)始使用json進(jìn)行數(shù)據(jù)傳輸,那么,如何快速簡(jiǎn)潔地用C語(yǔ)言進(jìn)行json的序列化和反序列化
    的頭像 發(fā)表于 10-07 11:05 ?1999次閱讀

    Java序列化怎么使用

    轉(zhuǎn)換方式就叫做序列化。將文件或者網(wǎng)絡(luò)傳輸中得到的 byte[] 數(shù)組轉(zhuǎn)換為 java 對(duì)象就叫做反序列化。 怎么使用 如果一個(gè) Java 對(duì)象要能被序列化,必須實(shí)現(xiàn)一個(gè)特殊
    的頭像 發(fā)表于 10-10 14:19 ?646次閱讀
    主站蜘蛛池模板: 成人综合激情 | 欧美一区二区三区在线 | 涩涩97在线观看视频 | 麻豆蜜桃 | 97午夜精品 | 国产成人夜间影院在线观看 | 亚洲欧美一区二区三区图片 | 色多多在线观看 | 国产精品爽爽影院在线 | 四虎在线播放免费永久视频 | 国内亚州视频在线观看 | 国产精品美女久久久久网站 | 久操视频在线播放 | 天天草比 | 男人j进人女人j 的视频 | 免费人成黄页在线观看日本 | 丁香花免费观看视频 | 欧美freesex交| 免费视频一级片 | 四虎在线观看 | 亚洲天天做夜夜做天天欢人人 | 六月婷婷七月丁香 | 午夜操操操 | 成人免费视频一区二区三区 | 国产一级淫 | 99热色| 日韩毛片网| 欧美一级看片a免费观看 | 尻逼尻逼| 很黄很污小说 | 一级特一级特色生活片 | 久久成人福利视频 | 成年免费大片黄在线观看免费 | 国产高清免费在线 | 狼人久久尹人香蕉尹人 | 国产黄色在线观看 | mmmxxx69日本 | 欧美影院一区二区三区 | 欧美性野久久久久久久久 | 欧美激情亚洲精品日韩1区2区 | 日本大片在线看 |