首页 > 代码库 > boost::serialization 拆分serialize函数

boost::serialization 拆分serialize函数

 在前篇

boost::serialization 用基类指针转存派生类(错误多多,一波三折)文中我们都是使用serialize函数来实现序列化,其代码格式如下:

private:
	friend class boost::serialization::access;
	template<typename Archive>
	void serialize(Archive& ar, const unsigned int version)
	{
		ar & BOOST_SERIALIZATION_NVP(name_);
		ar & BOOST_SERIALIZATION_VP(number_);
		ar & BOOST_SERIALIZATION_NVP(grade_);
	}
其实这个函数相当于两个函数:但我们使用xxx_oarchive时它等价于把对象数据save到文档中,
当我们使用xxx_iachive时它等价于把数据从文档中load给对象数据。因此可以它拆分成两个函数
save 和 load 函数。还用前面的例子。
save函数:

template<typename Archive>
void save(Archive& ar, const unsigned int version) const
{
	ar << BOOST_SERIALIZATION_NVP(name_);
	ar << BOOST_SERIALIZATION_NVP(number_);
	ar << BOOST_SERIALIZATION_NVP(grade_);
}
load函数:

template<typename Archive>
void load(Archive& ar, const unsigned int version)
{
	ar >> BOOST_SERIALIZATION_NVP(name_);
	ar >> BOOST_SERIALIZATION_NVP(number_);
	ar >> BOOST_SERIALIZATION_NVP(grade_);
}
最后需要加上一个宏:

BOOST_SERIALIZATION_SPLIT_MEMBER() //must be part of class
这个宏必须是在类的内部。其实这个宏实现了一个模版函数:

#define BOOST_SERIALIZATION_SPLIT_MEMBER()                       	template<class Archive>                                          	void serialize(                                                  	Archive &ar,                                                 	const unsigned int file_version                              	){                                                               	boost::serialization::split_member(ar, *this, file_version); } 
就是调用一个split_member函数,这个函数在头文件split_member.hpp中:

template<class Archive, class T>
inline void split_member(
		 Archive & ar, T & t, const unsigned int file_version
		)
{
	typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
		BOOST_DEDUCED_TYPENAME Archive::is_saving,
		mpl::identity<detail::member_saver<Archive, T> >, 
		mpl::identity<detail::member_loader<Archive, T> >
	>::type typex;//#1
	typex::invoke(ar, t, file_version);
}
#1使用traits技术推导出type类型,实际上这个type只有两种类型
template<class Archive, class T> struct member_saver;
template<class Archive, class T> struct member_loader;
这两个结构体中都有一个 invoke 函数(在头文件split_member.hpp中),但是
区分别调用类access 的 member_save 和 member_load 。而这两个函数则分别
调用我们自己定义的 save 和 load 函数。这也就是为什么要声明类boost::serialization::access
为友元类的原因:

template<class Archive, class T>
static void member_save(Archive & ar, 
						//const T & t,
						T & t,
						const unsigned int file_version
						)
{
	t.save(ar, file_version);//access类成员函数member_save,由此可见boost设计模式很复杂,但是值得学习
}
friend class boost::serialization::access;
//我们的save和load代码
这样access就可以调用我们写的save和load代码了。
好了现在来看完整代码吧:

class student_info
{
public:
	student_info() {}
	virtual ~student_info() {}
	student_info(const std::string& sn, const std::string& snm, const std::string& sg, const std::string& cs)
		: name_(sn), number_(snm), grade_(sg), class_(cs)
	{
	}

	virtual void print_info() const
	{
		std::cout << name_ << " " << number_ << " " << grade_ << " " << class_ << " ";
	}

private:
	//friend class boost::serialization::access;
	/*
	template<typename Archive>
	void serialize(Archive& ar, const unsigned int version)
	{
		ar & BOOST_SERIALIZATION_NVP(name_);
		ar & BOOST_SERIALIZATION_VP(number_);
		ar & BOOST_SERIALIZATION_NVP(grade_);
	}
    */
    friend class boost::serialization::access;//友元类这样它的成员函数member_save(load)就可以调用我们自己实现的save、load
	template<typename Archive>
	void save(Archive& ar, const unsigned int version) const
	{
		ar << BOOST_SERIALIZATION_NVP(name_);
		ar << BOOST_SERIALIZATION_NVP(number_);
		ar << BOOST_SERIALIZATION_NVP(grade_);
		ar << BOOST_SERIALIZATION_NVP(class_);
	}
    
	template<typename Archive>
	void load(Archive& ar, const unsigned int version)
	{
		ar >> BOOST_SERIALIZATION_NVP(name_);
		ar >> BOOST_SERIALIZATION_NVP(number_);
		ar >> BOOST_SERIALIZATION_NVP(grade_);
	}

	BOOST_SERIALIZATION_SPLIT_MEMBER() //must be part of class

private:
	std::string name_;
	std::string number_;
	std::string grade_;
};



接下来看一看以前前面的文章有个遗留的问题,就是那个serialize函数:

class student_info
{
public:
	//...
private:
	friend class boost::serialization::access;
	template<typename Archive>
	void serialize(Archive& ar, const unsigned int version)
	{
	ar & BOOST_SERIALIZATION_NVP(name_);
	ar & BOOST_SERIALIZATION_VP(number_);
	ar & BOOST_SERIALIZATION_NVP(grade_);
	}
	
private:
	std::string name_;
	std::string number_;
	std::string grade_;
};
这个函数是intrusive的,我们也可以用一种non-intrusive:

class student_info
{
public:
	//...
private:
	template<typename Archive>
	friend void serialize(Archive& ar, student_info &sdinfo, const unsigned int file_version);
private:
	std::string name_;
	std::string number_;
	std::string grade_;
};
再类外面实现 serialize 函数:

template<typename Archive>
void serialize(Archive& ar, student_info &sdinfo, const unsigned int file_version)
{
	ar & BOOST_SERIALIZATION_NVP(sdinfo.name_);
	ar & BOOST_SERIALIZATION_NVP(sdinfo.number_);
	ar & BOOST_SERIALIZATION_NVP(sdinfo.grade_);
}
这样就ok了。