Currently, the save/load methods inspect the Base object's creation key. If the key is blank, the object is serialized directly (a test class). If the key is not blank, the creation key is serialized (thus, a "production" class). Before this is done, a boolean flag is serialized indicating that a creation key was used to store the object or the object itself was stored. This is it, in rough form:
template <class Archive> void save(Archive& ar, unsigned int) const { bool flag = key.size() != 0;
ar << flag;
if (flag) { ar << my_base->key(); } else { ar << my_base; } }
template <class Archive> void load(Archive& ar, unsigned int) { bool flag;
ar >> flag;
if (flag) { string key; ar >> key; my_base = Factory::create(key); } else { ar >> my_base; } }
Now, this works just fine, but it is a bit inelegant (a friend calls this uninheritance).
This pretty much replicates what the serialization system does when serializing class marked with BOOST_CLASS_EXPORT
I would prefer to be able to encapsulate the logic of serialization in a separate class, something like this:
class BaseHandle { Base* my_base;
template <class Archive> void save(Archive& ar, unsigned int) const { // As above. }
template <class Archive> void load(Archive& ar, unsigned int) { // As above. }
};
Then, the Thing class, and any other class that would want to serialize a Base object would be straightforward:
class Thing { Base* my_base;
template <class Archive> void save(Archive& ar, unsigned int) const { ar << my_base; }
template <class Archive> void load(Archive& ar, unsigned int) { ar >> my_base; } };
The above is supported exactly as written by the serialization library
My question is: Has anyone else run across this type of pattern? I would prefer to use a shared pointer to the Base class throughout and to hide the constructors of all Base (and its derived classes), to force allocation of these objects through special static alloc methods that create shared_ptr-wrapped objects.
My problem is I don't quite know how to combine all of these ideas.
For example, using shared_ptr, class Thing would be quite simple:
typedef shared_ptr<Base> BasePtr;
class Thing { BasePtr my_base;
template <class Archive> void save(Archive& ar, unsigned int) const { ar << my_base; }
template <class Archive> void load(Archive& ar, unsigned int) { ar >> my_base; } };
The above is also supported exactly as written by the serialization library. Its in the documentation. The explanation particular to shared_ptr<T> is in the case study - shared_ptr;
However, now I've broken the previous work: I'd have to go back and put all of the serialization logic for factory construction back in the Thing class itself.
Hmmm - I far as I can see it was redundant in the first place.
If I try to combine all of this in the BaseHandle class, I run into difficulties:
... The above is what you want. In fact I would make it even simpler in this particular case: class Thing { shared_ptr<Base> my_base; template <class Archive> void serialize(Archive& ar, unsigned int) const { ar & my_base; } }; BOOST_SHARED_POINTER_EXPORT(DerivedProductionA) BOOST_SHARED_POINTER_EXPORT(DerivedProductionB) ... // other classes derived from Base I think that would be all that is necessary. Robert Ramey