Boost 序列化加载失败并抛出异常

发布于 2024-12-02 02:51:00 字数 4923 浏览 1 评论 0原文

我很长时间以来一直在努力让这项工作成功。

在我的项目中,有 6 个类正在使用 boost 中的确切教程通过实现模板函数序列化进行序列化。

这些类是:State、guState、Policy、Action、Param、Vec3D。

当我序列化并保存它们时,它工作正常。我确实得到了一个文本文件,其中包含各种数字和字符串。

没有抱怨,没有警告,没有抛出异常。唯一的情况是,如果我尝试序列化类的指针成员,空洞进程就会变成僵尸。所以我不尝试这样做,并保存作品。

然而,当我尝试加载时,我得到:

抛出实例后调用终止 “boost::archive::archive_exception”what():流错误

现在有趣的部分是我序列化了两个 boost::ptr_vector,一个由状态指针组成,另一个由策略指针组成。

状态向量,我保存并加载没有问题。 策略向量,我可以保存,但是当我尝试加载时,我得到了异常。

此外,在阅读了 boost 教程后,我的印象是,为了加载,除了序列化函数之外,我不需要任何其他东西。

然而,当我尝试加载时,boost 序列化会抱怨找不到默认构造函数,例如 State()、Policy() 等(我在每个类中实现了自己的构造函数)。

阅读本教程后,我实现了一个默认构造函数它什么也不做,因此升压序列化可以工作。确实编译通过了,我得到了上面提到的结果。

我尝试沿着我的老问题中看到的一条非常复杂的道路走下去,我尝试分离和实现 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();
}

有效包含两个保存状态和策略的 boost::ptr_vector。 状态的保存和加载没有问题。

加载策略时会出现问题。保存它们似乎不会产生问题(但我可能又错了)。

在不使用策略和使用策略的情况下测试保存/加载后,问题似乎与策略重建有关。

请注意仅由序列化使用的默认构造函数,如果没有它,代码将无法编译。

编辑#2:使用 valgrind 和 memcheck 运行应用程序后,它报告存在指针内存泄漏。然而,由于我不擅长使用 valgrind 进行调试,我无法真正判断泄漏发生在哪里,或者它是否与我的序列化相关(我认为是)。

I have been trying to make this work for a long time now.

In my project there are 6 classes that are being serialized using the exact tutorial from boost, by implementing the template function serialize.

Those classes are: State, guState, Policy, Action, Param, Vec3D.

When I serialize and save them, it works fine. I get indeed a text file, with various numbers and strings in it.

No complains, no warnings, no exceptions thrown. The only case is that if I try to serialize a pointer member of a class, the hole process becomes a zombie. So I do not try doing so, and saving works.

When however I try loading, I get:

terminate called after throwing an instance of
'boost::archive::archive_exception' what(): stream error

Now the interesting part is that I serialize two boost::ptr_vectors, one which consists of State pointers and one which consists of Policy pointers.

The state vector, I have saved and loaded without a problem.
The policy vector, I can save, but when I try loading i get the exception.

Furthermore, after reading the boost tutorials, I was under the impression that In order to load I did not need anything else other than the serialize function.

However when I tried loading, boost serialization would complain for not finding a default constructor such as State(), Policy(), etc (I implement my own constructors in each class ).

After reading this tutorial here I implemented a default constructor which does nothing, so that boost-serialization would work. Indeed it did compile, and I got the results mentioned above.

I have tried going down a much complicated road seen in my old question here where I tried seperating and implementing save_construct_data and load_construct_data, but I found this too instrusive, again I got the exact error as above.

Can someone please help me, explain how the loading works, what is the deal with the default constructors ? Or at least point me to a link that might be helpfull. I have gone through the manuals in boost, and they do not explain much about reconstruction.

Thank you.

Edit (Added a few snippets)

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);
}

Other Classes inheriting from State, have also their serialize functions, using:

  ar & boost::serialization::base_object<State>(*this);

Class Policy:

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);
}

As you can see those are the two main classes, Other classes are also serialized because of reconstruction dependencies ( class Action, class Param, etc )

The master Class:

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();
}

Effectively contains the two boost::ptr_vectors which hold the States and Policies.
States are saved and loaded without a problem.

The problem arises when loading policies. Saving them does not seem to create a problem (but then again I might be wrong).

Having tested save/load without policies, and with, The issue appears to be with policy reconstruction.

Note the default constructors used only by serialization, without which the code will not compile.

EDIT#2: After running application using valgrind and memcheck, it reports that there is a pointer memory leak. However since I am not good at debugging with valgrind I can't really tell where the leak is occuring or if it is relevant to my serialization (I think it is).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

掌心的温暖 2024-12-09 02:51:00

问题是您正在序列化状态和策略,而策略还保存对状态相同实例的引用。您只能序列化没有此类交叉引用的类。写入文件时,Boost应该抛出指针冲突异常。在我的测试中,它取决于是否抛出异常的写入顺序 - 这是不幸的,因为即使写入成功,加载也会失败。

解决方法是删除行 oa <<保存和加载时的状态,并在加载后步骤中手动修复指针。

关于构造函数:这主要是 boost-api 需要执行其模板魔法的东西。但是,在使用版本控制时,为成员变量指定默认值非常重要,这样在加载具有旧版本号的文件时它们就不会处于未初始化状态。

The problem is that you are serializing states and policies while Policy also holds references to the same instances of State. You can only serialize classes which don't have such cross-references. Boost should throw a pointer-conflict exception when writing to the file. In my tests it dependet on the order of writes if the exception was thrown or not - which is unfortunate because loading fails even if writing succeeded.

A workaround would be to delete the line oa << states when saving and loading and fix up the pointers by hand in a post-loading step.

About the constructors: it's mostly something the boost-api needs to do it's template magic. However when using versioning it's important to specify default-values for your member-variables so they are not left uninitialized when loading files with an older version-number.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文