我一直试图让这项工作很长时间。
在我的项目中,通过实现模板函数serialize,使用boost中的确切教程序列化了6个类。
这些类是:State,guState,Policy,Action,Param,Vec3D。
当我序列化并保存它们时,它工作正常。我确实得到了一个文本文件,里面有各种数字和字符串。
没有抱怨,没有警告,没有例外。唯一的情况是,如果我尝试序列化类的指针成员,则孔过程变为僵尸。所以我不尝试这样做,并保存工作。
然而,当我尝试加载时,我得到:
在抛出一个实例后终止调用 'boost :: archive :: archive_exception'what():stream error
现在有趣的部分是我序列化了两个boost :: ptr_vectors,一个由State指针组成,另一个由Policy指针组成。
状态向量,我已经保存并加载没有问题。 政策向量,我可以保存,但是当我尝试加载时,我得到了例外。
此外,在阅读了增强教程之后,我的印象是,为了加载我除了序列化函数之外不需要任何其他东西。
然而,当我尝试加载时,boost序列化会抱怨找不到默认构造函数,例如State(),Policy()等(我在每个类中实现自己的构造函数)。
在阅读this tutorial here之后,我实现了一个什么都不做的默认构造函数,因此boost-serialization可以工作。确实它确实编译了,我得到了上面提到的结果。
我试过在my old question here看到一条非常复杂的道路,在那里我尝试分离并实现了save_construct_data和load_construct_data,但我发现这太过于突兀,我再次得到了上面的确切错误。
有人可以帮助我,解释加载如何工作,默认构造函数的处理是什么?或者至少指出一个可能有用的链接。我已经阅读了boost中的手册,他们没有解释重建的内容。
谢谢。
编辑(添加了一些代码段)
class State
{
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version);
protected:
std::map<std::string,float> positions;
float reward;
std::size_t hash_value;
bool exists(const Action* A);
bool operator== (State const& S);
std::size_t hash();
void clean_noise();
State(){}; // NOTE: This is used only by serializer, without it, code won't compile
public:
enum position { standing, on_chest, on_back, on_left, on_right, getting_up };
position current_position;
Policy *my_policy;
Vec3D gps;
boost::ptr_vector<Action> actions;
State(ACTION_MODE &m);
~State();
bool operator== (State const* S);
bool operator< (State const* S) const ;
const float& getR() const;
bool addAction(Action *A);
Action* findAction(const Action *A);
boost::ptr_vector<Action>& getAllActions();
void printState();
virtual bool isTerm();
};
template <class Archive>
void State::serialize(Archive& ar, const unsigned int version)
{
ar & BOOST_SERIALIZATION_NVP(positions);
ar & BOOST_SERIALIZATION_NVP(gps);
ar & BOOST_SERIALIZATION_NVP(current_position);
ar & BOOST_SERIALIZATION_NVP(reward);
ar & BOOST_SERIALIZATION_NVP(hash_value);
ar & BOOST_SERIALIZATION_NVP(actions);
ar & BOOST_SERIALIZATION_NVP(my_policy);
}
继承自State的其他类,还有它们的序列化函数,使用:
ar & boost::serialization::base_object<State>(*this);
课程政策:
class Policy
{
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version);
Policy() {}; // NOTE: Again same as with state, used only by serialize load
protected:
float QValue;
State *state;
public:
//! Base class constructor
Policy(State *s);
...
};
template <class Archive>
void Policy::serialize(Archive& ar, const unsigned int version)
{
ar & BOOST_SERIALIZATION_NVP(action);
ar & BOOST_SERIALIZATION_NVP(state);
ar & BOOST_SERIALIZATION_NVP(QValue);
ar & BOOST_SERIALIZATION_NVP(r);
}
正如您所看到的那些是两个主要类,其他类也因为重建依赖性而被序列化(类Action,类Param等)
大师班:
template <class S, class P> class Task
{
protected:
...
//! Container of states of type S (template parameter)
boost::ptr_vector<S> states;
//! Container of policies of type P (template parameter)
boost::ptr_vector<P> policies;
...
public:
Task(Agent &a, ACTION_MODE &m);
...
void save_to_file();
void load_from_file(std::string filename);
};
template <class S, class P>
void Task<S,P>::save_to_file()
{
std::string output = ramdisk+"serialized";
char *file = (char*)output.c_str();
std::ofstream ofs(file);
assert(ofs.good());
boost::archive::text_oarchive oa(ofs);
oa << states;
oa << policies;
ofs.close();
}
template <class S, class P>
void Task<S,P>::load_from_file(std::string filename)
{
char *file = (char*)output.c_str();
std::cout << file << std::endl;
std::ifstream ifs(file);
boost::archive::text_iarchive ia(ifs);
ia >> states;
ia >> policies;
ifs.close();
}
有效地包含两个包含States和Policies的boost :: ptr_vectors。 保存和加载状态没有问题。
加载政策时出现问题。保存它们似乎不会产生问题(但我可能再次出错)。
在没有策略的情况下测试了保存/加载,以及,问题似乎与策略重建有关。
请注意默认构造函数仅用于序列化,否则代码将无法编译。
编辑#2:使用valgrind和memcheck运行应用程序后,它报告存在指针内存泄漏。但是因为我不善于使用valgrind进行调试,所以我无法确定泄漏发生的位置或者是否与我的序列化相关(我认为是)。
答案 0 :(得分:3)
问题在于您是序列化states
和policies
,而Policy
也包含对State
的相同实例的引用。您只能序列化没有此类交叉引用的类。在写入文件时,Boost 应抛出指针冲突异常。在我的测试中,如果抛出异常,它依赖于写入的顺序 - 这是不幸的,因为即使写入成功,加载也会失败。
解决方法是在保存和加载时删除行oa << states
并在后加载步骤中手动修复指针。
关于构造函数:它主要是boost-api需要做的模板魔术。但是,在使用版本控制时,为成员变量指定默认值非常重要,因此在加载具有旧版本号的文件时,它们不会保持未初始化状态。