I'm new to C++ boost, so this question may be basic: How to serialize two classes which refers to each other with pointer. e.g.:
class A;
class B;
class A {
public:
...
private:
double a;
vector <B*> b;
}
class B {
public:
...
private:
int b;
list <A*> a;
}
class A has a private vector contains pointer B*, while class B has a private list contains A*.
Especially by Deserialization there will be problem (the pointer!). Does any one has idea?
Boost.Serialization will handle circular references of pointers just fine, thanks to object tracking.
If you serialize an object through a pointer, object tracking is used by default. It also comes with a serializer for std::vector
(include boost/serialization/vector.hpp
).
Boost.Serialzation will keep track of the addresses of objects you serialize. If it encounters an address that was already serialized, it will store a 'reference' to the object rather than serializing it again.
When deserializing, it will resolve these references to the proper addresses as it encounters them (which implies that they must be pointers so that addresses can be assigned to them).
The only restriction is, that the referenced objects must be allocated dynamically (on the heap). You can serialize an object on the stack as long as it is not referenced by another one.
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;
The reason for this is: b is first encountered as a pointer when serializing a (in its vector). When serializing b itself, only a reference to b is stored.
A a;
B b;
archive >> a >> b; // crashes when deserializing b!
When deserializing a, the b will be allocated in the vector. And now you want to restore b which already exists on the stack. Since you cannot assign a new address to a variable on the stack, it will crash!
Correct:
A* a = new A();
B* b = new B();
a.vec.push_back(b); // OK! this works fine
When deserializing b, boost will simply assign the address of the b inside the vector of a to it.
Boost.Serialzation also comes with a serializer for boost::shared_ptr
(include boost/serialization/shared_ptr.hpp
) which may make your task even easier by
using std::vector< boost::shared_ptr<A> >
instead so you won't have to worry freeing the memory.
With the basics covered, you can implement the serialization of your classes as simple as this:
// 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
}
No change is needed if you choose to use a vector of shared_ptrs (just include the header).