派生クラスをベースクラスポインタを使用してシリアライズするときに、ブーストのシリアライゼーションに問題があります。いくつかのオブジェクトがシステムで受信されるときにそれらを直列化するシステムが必要なので、私は時間の経過とともにシリアル化する必要があります。 boost::archive::binary_oarchive
を開き、必要に応じてオブジェクトをシリアル化できるので、これは実際問題ではありません。急速に私は、メモリアドレスによるオブジェクトトラッキングを実行していることに気付きました。最初の問題は、同じメモリアドレスを共有する異なるオブジェクトが同じオブジェクトとして保存されたことでした。これは、必要な派生クラスで次のマクロを使用して固定することができます。Boost(C++)でのクラストラッキングのない派生クラスのシリアライゼーション
BOOST_CLASS_TRACKING(className, boost::serialization::track_never)
これは正常に動作しますが、基本クラスが抽象的でない場合、再び、ベースクラスが適切にシリアライズされていません。次の例では、基本クラスの直列化メソッドは、最初のオブジェクトで1回だけ呼び出されます。以下では、オブジェクトは異なる型を持っていますが、このオブジェクトは前もってシリアル化されていると仮定しています。
#include <iostream>
#include <fstream>
#include <boost/serialization/export.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/archive/archive_exception.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
using namespace std;
class AClass{
public:
AClass(){}
virtual ~AClass(){}
private:
double a;
double b;
//virtual void virtualMethod() = 0;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & a;
ar & b;
cout << "A" << endl;
}
};
//BOOST_SERIALIZATION_ASSUME_ABSTRACT(Aclass)
//BOOST_CLASS_TRACKING(AClass, boost::serialization::track_never)
class BClass : public AClass{
public:
BClass(){}
virtual ~BClass(){}
private:
double c;
double d;
virtual void virtualMethod(){};
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & boost::serialization::base_object<AClass>(*this);
ar & c;
ar & d;
cout << "B" << endl;
}
};
// define export to be able to serialize through base class pointer
BOOST_CLASS_EXPORT(BClass)
BOOST_CLASS_TRACKING(BClass, boost::serialization::track_never)
class CClass : public AClass{
public:
CClass(){}
virtual ~CClass(){}
private:
double c;
double d;
virtual void virtualMethod(){};
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & boost::serialization::base_object<AClass>(*this);
ar & c;
ar & d;
cout << "C" << endl;
}
};
// define export to be able to serialize through base class pointer
BOOST_CLASS_EXPORT(CClass)
BOOST_CLASS_TRACKING(CClass, boost::serialization::track_never)
int main() {
cout << "Serializing...." << endl;
{
ofstream ofs("serialization.dat");
boost::archive::binary_oarchive oa(ofs);
for(int i=0;i<5;i++)
{
AClass* baseClassPointer = new BClass();
// serialize object through base pointer
oa << baseClassPointer;
// free the pointer so next allocation can reuse memory address
delete baseClassPointer;
}
for(int i=0;i<5;i++)
{
AClass* baseClassPointer = new CClass();
// serialize object through base pointer
oa << baseClassPointer;
// free the pointer so next allocation can reuse memory address
delete baseClassPointer;
}
}
getchar();
cout << "Deserializing..." << endl;
{
ifstream ifs("serialization.dat");
boost::archive::binary_iarchive ia(ifs);
try{
while(true){
AClass* a;
ia >> a;
delete a;
}
}catch(boost::archive::archive_exception const& e)
{
}
}
return 0;
}
コードのこの部分を実行する場合、結果は次の通りである:
派生クラスが明示的track_neverフラグを有するができるように、基本クラスのみ、一度シリアル化されています。この動作を修正するには、2つの異なる回避策があります。最初の方法は、基本クラスを純粋な仮想メソッドで抽象化し、マクロBOOST_SERIALIZATION_ASSUME_ABSTRACT(Aclass)
を呼び出すことです。もう1つは、track_neverフラグを基底クラス(コード内にコメントされている)に入れます。
システム状態の将来の厳密なシリアル化を実行したいと思っています。これは、特定のDClass拡張A(BまたはCではなく)を追跡する必要があります。また、AClassは抽象的ではない。
ヒント明示的にベースクラスの直列化メソッドを呼び出す方法はありますか?これは、ベースクラスのトラッキング機能を避けることです(既に派生クラスでは無効になっています)。
boostが仮想でないと仮定することもできます( 'BOOST_SERIALIZATION_ASSUME_ABSTRACT(Aclass)'行のコメントを外してコンパイルしようとしています)? – Synxis