c++ - 提升 :serialization reconstruction (loading)

标签 c++ boost-serialization

我正在使用 boost:serialization 将数据结构保存到文件中。实际数据是类和子类的指针 vector 。 然而,被序列化的类的构造函数将另一个实例化类 Agent 作为参数,它是一个控制与模拟 API (webots) 通信的对象。 我在 boost::serialization 示例中看到,可序列化对象需要一个空的构造函数 class() {};用于重建。然而,这对我来说是不切实际的。我如何使用重建但包含与 API 通信的对象? 其中一个可序列化类具有此构造函数:

State(Agent &A, ACTION_MODE const& m);

并且我从 boost 文档中的示例中看到我需要这样的东西:

State() {};

但是 Agent &A 必须作为参数传递。 我应该找到解决这个问题的方法(使用外部、单例、全局对象)还是有办法在重建时修改这种行为?我确定我在这里遗漏了一些东西。

谢谢

编辑: 也许我没有足够清楚地解释这一点。尝试通过重构序列化数据“加载”时收到错误消息。

error: no matching function to call State::State()

这让我研究了 boost::serialize 代码,并认为它正在调用构造函数或复制运算符。 我如何让它使用特定的构造函数来序列化数据并将代理引用 &a 作为参数?

编辑#2:

template <class S, class P, class A> void Task<S,P,A>::save(const char* file)
{
  std::ofstream ofs(file);
  assert(ofs.good());
  boost::archive::text_oarchive oa(ofs);
  oa << states;
  ofs.close();
}

template <class S, class P, class A> void Task<S,P,A>::load(const char* file)
{
  std::ifstream ifs(file);
  boost::archive::text_iarchive ia(ifs);
  ia >> states;
  ifs.close();
}

States 是 boost::serialization::access 的 friend ,并且有一个函数 serialize。 保存工作正常,加载是问题。 状态是:boost::ptr_vector<S> states;其中 S 是一种 State 多态类。

State是基类,有“serialize”

template <class Archive>
void State::serialize(Archive& ar, const unsigned int version)
{
  ar & accel.Xaxis & accel.Yaxis & accel.Zaxis;
  ar & gyro.Xaxis & gyro.Yaxis & gyro.Zaxis;
  ar & gps.Yaxis;
  ar & positions;
  ar & reward & value & hash_value;
}

guState 继承自 State。

template <class Archive>
void guState::serialize(Archive& ar, const unsigned int version)
{
  ar & boost::serialization::base_object<State>(*this);
  ar & accel.Xaxis & accel.Yaxis & accel.Zaxis;
  ar & gyro.Xaxis & gyro.Yaxis & gyro.Zaxis;
  ar & gps.Yaxis;
  ar & positions;
  ar & reward & value & hash_value;
}

accel、gyro、gps 是具有 3 个 double 变量的简单结构。他们在上面连载^^。 职位是 std::map<std::string,float> positions;

查看序列化文本文件,一切正常。 我不明白为什么它在尝试加载文件时调用构造函数。

编辑#3:

基础构造函数是:

State(Agent &A, ACTION_MODE const& m);

派生构造函数是:

guState::guState(Agent& A, ACTION_MODE const& m) : 
State(A, m)
{
...
}

代理引用 &A,保存在每个状态(或派生状态)中,指的是从模拟 API 中获得的对象。它控制着一个机器人。我不能序列化它,序列化它也没有意义。

当我使用时:

namespace boost { namespace serialization {
  template <class Archive>
    void save_construct_data(Archive & ar,const guState* d,const unsigned int file_version)
    {
      ar << guState::caller;
      ar << guState::mode;
    }
   template <class Archive>
   void load_construct_data(Archive & ar, guState* d,const unsigned int file_version)
   {
      Agent &a;
      ACTION_MODE &m;
      ar >> a;
      ar >> m;
      ::new(d) guState(a,m);
   }
  }
}

我收到以下错误:

invalid use of non-static data member State::caller
invalid use of non-static data member State::mode

引用从构造函数中使用的引用。 并且:

error: 'a' declared as reference but not initialized
error: 'm' declared as reference but not initialized

如您所见,尝试保存对 Agent 的引用是没有意义的,因为每次启动应用程序时该引用(即使它可以保存或序列化)都可能不同。

并且在加载构造数据时,除了我可能使用了错误的语法外,从对代理的序列化引用构造是没有意义的。

我相信我需要的是一种方法来告诉 load_construct_data 如何获取对代理的引用(在初始化代理对象之后)并使用该引用来构造数据。

这有意义吗?你认为这可行吗?

编辑#4

namespace boost { namespace serialization {
  template <class Archive>
    void save_construct_data(Archive & ar,const guState* d,const unsigned int file_version)
    {
      ar <<  guState::caller;
    }
   template <class Archive>
   void load_construct_data(Archive & ar, guState* d,const unsigned int file_version)
   {
      Agent * a;
      ACTION_MODE mode = RAND_SING;
      ar >> a;
      ::new(d) guState(*a,mode);
   }
  }
}

不允许序列化 guState::caller

我还使类 Agent 可序列化,并重载了 Agent 的 load_construct_data 和 save_construct_data,以便从模拟应用请求一个新的 Agent 实例来控制 API。

最佳答案

编辑:

我认为我们都错过了手册的一部分:非默认构造函数 here .要使其正常工作,您需要一个 save_construct_data 和一个 load_construct_data 函数。在探索这些 friend 的地方方面存在轻微的技术问题 here .

此外,您说您在尝试仅加载时遇到了这个问题,但您可以保存。这让我觉得你可能忽略了

BOOST_CLASS_EXPORT_GUID(state, "state")

这种遗漏可能会在您进行负载编译后导致段错误(请参阅手册的导出部分)

为了确保我没有弄错,我做了一个编译示例,我添加它以防它有用。

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <boost/serialization/export.hpp>
#include <iostream>
#include <fstream>

//base class
struct base
{
  base(double d) : m_d(d) {}
  virtual double run() = 0;
private:

  friend class boost::serialization::access;
  double m_d;
  template <class Archive>
  void serialize(Archive& ar, const unsigned int version)
  {
    ar & m_d;
  }
};

//forward declare the save construct data before friending it 
// (something about friend being in a different namespace)
class derived;
namespace boost { namespace serialization {
template<class Archive>
inline void save_construct_data(Archive & ar, const derived * t, const unsigned int file_version);
}}


//derived class with non-default constructor
struct derived : public base
{
  derived(double a , double b) : 
    base(a+b),
    m_a(a),m_b(b),m_c(a*b) 
  {}
  //some checks
  double get_a() const {return m_a;}
  double get_b() const {return m_b;}
  double get_c() const {return m_c;}

  double run(){return 1.0;}
private:

  friend class boost::serialization::access;
  template<class Archive> 
  friend void boost::serialization::save_construct_data(Archive & ar, const derived * t, const unsigned int file_version);

  template <class Archive>
  void serialize(Archive& ar, const unsigned int version)
  {
    ar & boost::serialization::base_object<base>(*this);
    //only need to return c, a and b already done for constructor
    ar & m_c;
  }
  double m_a, m_b, m_c;
 };

//Save and load the data required for the constructor.
namespace boost { namespace serialization {
  template <class Archive>
    inline void save_construct_data(
                    Archive & ar,const derived* d,const unsigned int file_version
                    )
    {
      // save data required to construct instance
      ar << d->m_a;
      ar << d->m_b;
    }
    template <class Archive>
    inline void load_construct_data(
                        Archive & ar, derived* d,const unsigned int file_version
                        )
    {
      double a,b;
      ar >> a;
      ar >> b;
    // invoke inplace constructor to initialize instance of my_class
      ::new(d) derived(a,b);
    }

  }
}

//register the derived class with boost.
BOOST_CLASS_EXPORT_GUID(derived, "derived")

int
main  (int ac, char **av)
{
  std::ofstream ofs("filename");
  base* p = new derived(2,3);

  // save data to archive
  {
    boost::archive::text_oarchive oa(ofs);
    oa << p;
  }

  // ... some time later restore the class instance to its orginal state
  base* p2;
  {
     std::ifstream ifs("filename");
     boost::archive::text_iarchive ia(ifs);
     ia >> p2;
  }

  derived* d = static_cast<derived*>(p2);
  std::cout<<"p2 vals are: "<<d->get_a()<<" "<<d->get_b()<<" "<<d->get_c()<<std::endl;

}

旧回复:

不确定我是否完全理解您的问题(更完整的示例会对我有所帮助)- 序列化对象时通常不会使用构造函数:序列化原始数据?

你的意思是不想序列化对象的所有原始数据,而只是想在反序列化对象(使用构造函数)时再次重构它?如果是这样,那么您可以通过序列化重建所需的数据并拆分保存和加载操作来实现这一点。

struct my_class
{
  my_class(Agent& A, ACTION_MODE const & m)
    : m_state(A,M)
  {}


private: 

  State m_state;

  friend class boost::serialization::access;
  void save(Archive & ar, const unsigned int version) const
  {
      // note, version is always the latest when saving
      Agent tmp_A = m_state.get_A();
      ACTION_MODE tmp_m = m_state.get_m();
      ar & tmp_A; 
      ar & tmp_m;
  }
  template<class Archive>
  void load(Archive & ar, const unsigned int version)
  {
      Agent tmp_A;
      ACTION_MODE tmp_m
      ar & tmp_A; 
      ar & tmp_m;
      m_state = State(tmp_A,tmp_m);
  }
  BOOST_SERIALIZATION_SPLIT_MEMBER()
}

这有帮助吗,还是我没捕获要点?

关于c++ - 提升 :serialization reconstruction (loading),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6734814/

相关文章:

C++ 动态(多阶段)3D vector 实例化和元素分配

c++ - Boost::Serialization:如何避免指针的双重保存? (并出现 free.c 错误)

c++ - 使用 boost::serialization 的序列化树结构

C++ Boost.Serialization - 用户定义成员的非侵入式序列化?

c++ - boost::archive::text_oarchive 的简单扩展

c++ - 在二进制存档中使用Boost序列化时出错

c++ - Visual Studio 2010 的全局源代码控制忽略模式中应包含哪些内容?

C++ 指针数组

c++ - 如何减轻 C++ 中由于虚函数调用而导致的分支错误预测?

c++ - vector 重新分配使用复制而不是 move 构造函数