4

私はboost:serializationを使用してデータ構造をファイルに保存しています。実際のデータは、クラスとサブクラスのポインターベクトルです。ただし、シリアル化されるクラスのコンストラクターは、シミュレーションAPI(webots)との通信を制御するオブジェクトである別のインスタンス化されたクラスAgentをパラメーターとして受け取ります。boost :: serializationの例では、シリアル化可能なオブジェクトには空のコンストラクターclass(){}が必要であることがわかります。再建に使用されます。しかし、私の場合、これは実用的ではありません。再構築を使用する方法はありますが、APIと通信するオブジェクトを含めることができますか?シリアル化可能なクラスの1つには、次のコンストラクターがあります。

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

ブーストドキュメントの例から、次のようなものが必要であることがわかりました。

State() {};

ただし、エージェント&Aはパラメータとして渡す必要があります。これを回避する方法(extern、シングルトン、グローバルオブジェクトを使用)を見つける必要がありますか、それとも再構築時にこの動作を変更する方法がありますか?私はここで何かが欠けていると確信しています。

ありがとうございました

編集:たぶん私はこれを十分に明確に説明していませんでした。シリアル化されたデータを再構築して「ロード」しようとすると、エラーメッセージが表示されます。

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

これが私がboost::serializeコードを調べた理由であり、コンストラクターまたはコピー演算子を呼び出していると思います。特定のコンストラクターを使用してデータをシリアル化し、引数としてエージェント参照を取得するにはどうすればよいですか?

編集#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の友だちであり、serialize機能を備えています。保存は正常に機能し、読み込みが問題になります。状態は次のとおりです。boost::ptr_vector<S> states;ここで、Sは状態ポリモーフィッククラスの一種です。

状態は基本クラスであり、「シリアル化」されています

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

ご覧のとおり、エージェントへの参照を保存しようとしても意味がありません。その参照は(保存またはシリアル化できたとしても)、アプリケーションが起動するたびに異なる可能性があるためです。

そして、構成データをロードする際に、おそらく間違った構文を使用していることを除けば、エージェントへのシリアル化された参照から構成することは意味がありません。

私が必要だと信じているのは、(エージェントオブジェクトを初期化した後)エージェントへの参照を取得し、その参照を使用してデータを構築する方法を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をシリアル化可能にし、シミュレーションアプリからAPIを制御するためのAgentの新しいインスタンスを要求するために、Agentのload_construct_dataとsave_construct_dataをオーバーロードしました。

4

1 に答える 1

4

編集:

私たちが両方とも見逃したと思われるマニュアルの部分があります:ここにデフォルト以外のコンストラクター のセクションがあります。それを機能させるには、関数が必要です。これらがここで探究されている場所に関しては、わずかな専門性があります。save_construct_dataload_construct_data

また、ロードのみを試みたときにこの問題が発生したが、問題なく保存できたとおっしゃいました。これはあなたが省略したかもしれないと私に思わせます

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

それは役に立ちますか、それとも要点を逃しましたか?

于 2011-07-18T15:19:08.303 に答える