私は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をオーバーロードしました。