老所工作室 : boost::serialization库之对象状态的保存
来源:互联网 发布:淘宝网魅族 编辑:程序博客网 时间:2024/05/17 01:42
http://blog.ipattern.org/archives/18
关于对象的序列化,是OO语言中的一个重要内容。然而,作为C++语言的标准库,STL并没有提供对序列化的支持。还好,我们还有boost这个“准标准”库,它倒是提供了序列化的支持。让我们来看看它都有些什么能耐吧。
首先,我们定义一个用于测试的类:
#include
#include
using namespace std;
class log_entry
{
int _count;
public:
log_entry() : _count(0) {};
const int& count() const { return _count; };
void count_inc() { _count++; };
};
我们创建一个日志条目类,里面包含一个计数器。我们计划通过保存该对象不同时刻的状态,来组成一个连续的日志。换句话说,我们希望用一系列不同状态的日志条目对象,来组成一个完整的日志。
要使用boost::serialization
库来保存对象,我们还需要添加方法,使得该类是“可序列化的”。boost库提供两种方式来使对象可序列化:在类内部添加序列化接口,或者不改变类的定义,添加全局的针对该类的序列化函数。这里,我们采取第一种方法。关于第二种方法,可以参考其在线的教程。
#include
#include
#include
using namespace std;
class log_entry
{
friend class boost::serialization::access;
int _count;
template
void serialize(Archive& ar, const unsigned int version)
{
ar & _count;
};
public:
log_entry() : _count(0) {};
const int& count() const { return _count; };
void count_inc() { _count++; };
};
首先,需要为boost::serialization::access
授权访问该类的私有成员,其次添加一个标准的serialize
函数。这个函数将保存/读取融合到了一个函数,当保存时,Archive
的&操作就是保存,反之则是读取。第二个参数是一个用于归档的版本管理,我们这里暂时先不考虑。
那么对于实际操作,我们的步骤就是,先构造一个归档对象,然后用<<
和>>
操作符来保存和读取对象的状态:
int main(int, char**)
{
// create archive, we use string stream, instead of file stream
ostringstream so;
boost::archive::text_oarchive ao(so);
// now change object state, and snapshot it into archive
log_entry entry;
entry.count_inc();
ao << entry;
entry.count_inc();
entry.count_inc();
ao << entry;
// now we freeze serialized string, and use it create input
// archive.
istringstream si(so.str());
boost::archive::text_iarchive ai(si);
// we use another object, to restore object
log_entry entry_2;
ai >> entry_2;
cout << "1st state is: " << entry_2.count() << endl;
ai >> entry_2;
cout << "2nd state is: " << entry_2.count() << endl;
return 0;
}
注意,我们引入了text类型的输入和输出archive,所以需要在头文件区域加上:
#include
#include
这段代码保存了两个状态,希望第一个状态输出1,第二个状态输出3。代码的逻辑很简单,想必也没有错了,那么我们用以下命令来进行编译:(如果没有安装boost_serialization清根据具体操作系统进行安装)
] g++ -o test -lboost_serialization test.cpp
你一定很惊讶,这么简单的代码,怎么也会出错:
soloman@ninja-ubuntu:~/Temp$ g++ -o test -lboost_serialization test.cpp
/usr/include/boost/archive/detail/oserializer.hpp: In function
‘void boost::archive::save(Archive&, T&) [with Archive =
boost::archive::text_oarchive, T = log_entry]’:
/usr/include/boost/archive/detail/common_oarchive.hpp:62: instantiated
from ‘void
boost::archive::detail::common_oarchive
int) [with T = log_entry, Archive =
boost::archive::text_oarchive]’
/usr/include/boost/archive/basic_text_oarchive.hpp:75: instantiated
from ‘void
boost::archive::basic_text_oarchive
int) [with T = log_entry, Archive =
boost::archive::text_oarchive]’
/usr/include/boost/archive/detail/interface_oarchive.hpp:79:
instantiated from ‘Archive&
boost::archive::detail::interface_oarchive
[with T = log_entry, Archive = boost::archive::text_oarchive]’
test.cpp:36: instantiated from here
/usr/include/boost/archive/detail/oserializer.hpp:566: 错误:
‘sizeof’ 不能用于不完全的类型
‘boost::STATIC_ASSERTION_FAILURE
而且,这个错误还非常奇怪。其实,库的作者早就料定我们会碰到这个错误了,在在线文档中,专门有一节文字用来解释这个“编译时的陷阱”。
原来,这个序列化库有个功能,是对象的跟踪,也就是保证同一个对象在序列化里面只有一个实例,而其他对该对象的引用则直接序列化一个对已存在对象的
指针引用。那么在我们这段代码里,我们对对象entry序列化了两次,而序列化库用来判断两个对象是否是同一对象的标志就是其指针。我们的entry对象
是声明在栈上的,所以两次序列化时,其指针是相同的。serialization库认为你这样做是不符合逻辑的,所以通过编译时的错误来终止错误的继续。
但是,这个逻辑对我们来说确实正确的,我们并不想为每个状态都新产生一个对象,我们实际上是想“冻结”该对象在各个时刻时
的状态,并在序列化流里保存许多该状态时对象的副本。在编译器报错后,我们不得不再次慎重地考虑了一下我们的逻辑,确认无误后,接下来就是要怎么告诉编译
器:我确保,我的逻辑是正确的,一切后果我自负!
有两个方法,一是关闭对象跟踪,二是通过const cast添加一个语意来确保我们的逻辑。第二个方法其实就是显式地进行对象状态“冻结”,很多时候,我们应该选择“显式”,避免”隐式“:
int main(int, char**)
{
// create archive, we use string stream, instead of file stream
ostringstream so;
boost::archive::text_oarchive ao(so);
// now change object state, and snapshot it into archive
log_entry entry;
// create object freeze!
const log_entry& entry_freeze = const_cast(entry);
entry.count_inc();
ao << entry_freeze;
entry.count_inc();
entry.count_inc();
ao << entry_freeze;
// now we freeze serialized string, and use it create input
// archive.
istringstream si(so.str());
boost::archive::text_iarchive ai(si);
// we use another object, to restore object
log_entry entry_2;
ai >> entry_2;
cout << "1st state is: " << entry_2.count() << endl;
ai >> entry_2;
cout << "2nd state is: " << entry_2.count() << endl;
return 0;
}
这样,一个const_cast
代表我们显式地同意打破对象跟踪原则,便于代码逻辑的表达。这样修改后,编译通过,我们获得了正确的输出:
soloman@ninja-ubuntu:~/Temp$ ./test
1st state is: 1
2nd state is: 3
当然,有兴趣的话,我们也可以添加代码将序列化的字符串打印出来瞧瞧。
下面是完整的测试代码test.cpp:
#include
#include
#include
#include
#include
using namespace std;
class log_entry
{
friend class boost::serialization::access;
int _count;
template
void serialize(Archive& ar, const unsigned int version)
{
ar & _count;
};
public:
log_entry() : _count(0) {};
const int& count() const { return _count; };
void count_inc() { _count++; };
};
int main(int, char**)
{
// create archive, we use string stream, instead of file stream
ostringstream so;
boost::archive::text_oarchive ao(so);
// now change object state, and snapshot it into archive
log_entry entry;
// create object freeze!
const log_entry& entry_freeze = const_cast(entry);
entry.count_inc();
ao << entry_freeze;
entry.count_inc();
entry.count_inc();
ao << entry_freeze;
// what's inside serialized string?
cout << "==== serialized string ====" << endl;
cout << so.str() << endl;
cout << "===========================" << endl;
// now we freeze serialized string, and use it create input
// archive.
istringstream si(so.str());
boost::archive::text_iarchive ai(si);
// we use another object, to restore object
log_entry entry_2;
ai >> entry_2;
cout << "1st state is: " << entry_2.count() << endl;
ai >> entry_2;
cout << "2nd state is: " << entry_2.count() << endl;
return 0;
}
附带输出序列化字符串的输出为:
soloman@ninja-ubuntu:~/Temp$ ./test
==== serialized string ====
22 serialization::archive 4 0 0 1 3
===========================
1st state is: 1
2nd state is: 3
- 老所工作室 : boost::serialization库之对象状态的保存
- boost::serialization库之对象状态的保存
- 对象序列化之Boost.Serialization
- boost的Serialization库的问题?
- 利用boost的serialization库实现c++对象的序列化与反序列化
- Boost Serialization库使用
- Boost Serialization 库
- Boost Serialization 库
- Boost Serialization 库
- Boost库-Serialization-发布信息
- Boost Serialization 库(一个有效的调试工具)
- boost::serialization
- boost serialization
- boost::serialization
- boost serialization
- boost::serialization
- Boost serialization
- boost.serialization中基类指针容器存子类对象的序列化
- C# 选择目录
- Ajax 三剑客源码及在线文档
- Tomcat启动内存显示不足
- UML 活动图
- CPU 组织
- 老所工作室 : boost::serialization库之对象状态的保存
- 统一建模语言UML轻松入门之综合实例
- 中国历史上影响最大的10首诗
- 开发者经常重新发明而不是重用的.NET工具类
- 奥运圣火门口过 广东四市公布奥运圣火路线图
- 推荐google《数学之美系列》
- UML建模工具比较
- jsp-定义带标签体的标签
- 2008北京奥运圣火传递线路图