オブジェクト追跡のおかげで、Boost.Serialization はポインターの循環参照を適切に処理します。ポインターを使用してオブジェクトをシリアル化する場合、既定でオブジェクト トラッキングが使用されます。std::vector
(include )のシリアライザーも付属していboost/serialization/vector.hpp
ます。
Boost.Serialzation は、シリアル化するオブジェクトのアドレスを追跡します。既にシリアル化されているアドレスに遭遇した場合、再度シリアル化するのではなく、オブジェクトへの「参照」を保存します。
デシリアライズするとき、これらの参照を見つけたときに適切なアドレスに解決します (これは、アドレスを割り当てることができるように、それらがポインターでなければならないことを意味します)。
唯一の制限は、参照されるオブジェクトが (ヒープ上で) 動的に割り当てられる必要があることです。別のオブジェクトから参照されていない限り、スタック上のオブジェクトをシリアル化できます。
A a;
B b;
a.vec.push_back( &b ); // WRONG! deserialization will crash
// if a does not reference to b, it will work
archive << a << b;
その理由は次のとおりです。bは、a を(そのベクトルで)シリアル化するときにポインターとして最初に検出されます。b自体をシリアル化すると、 bへの参照のみが格納されます。
A a;
B b;
archive >> a >> b; // crashes when deserializing b!
a を逆シリアル化すると、bがベクターに割り当てられます。そして、スタック上に既に存在するbを復元したいとします。スタック上の変数に新しいアドレスを割り当てることができないため、クラッシュします!
正しい:
A* a = new A();
B* b = new B();
a.vec.push_back(b); // OK! this works fine
bを逆シリアル化する場合、boost は単に a のベクトル内の b のアドレスをそれに割り当てます。
Boost.Serialzation にはboost::shared_ptr
(include boost/serialization/shared_ptr.hpp
) のシリアライザーも付属しており、代わりに使用することでタスクがさらに簡単になる可能性があるためstd::vector< boost::shared_ptr<A> >
、メモリの解放を心配する必要はありません。
基本をカバーすると、クラスのシリアル化を次のように簡単に実装できます。
// add this to your classes you want to serialize
private:
friend boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, unsigned version) {
//TODO: serialize other member variables
ar & BOOST_SERIALIZATION_NVP(vec); // vec is a std::vector
}
shared_ptrs のベクトルを使用することを選択した場合、変更は必要ありません (ヘッダーを含めるだけです)。