I am currently working on a software project that requires object persistence as part of its implementation. The boost serialization library seemed to fit the job perfectly at first glance, but now that I've tried to use it I am seriously starting to question its overall design.
The library wants the user to define a serialize method for each class the user wants to serialize.
class Object
{
private:
int member;
public:
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & member;
}
};
This is problematic if the class in question has member objects which are part of other third party libraries and APIs. Even though the ones that I happen to use are all available under the zlib license, modifying library header just feels wrong.
But the developers have thought of that and provided a non intrusive version that allows to add serialization to classes without ever modifying them. Brilliant.
template<class Archive>
void serialize(Archive & ar, Object& o, const unsigned int version)
{
ar & o.member;
}
But alas, this doesn't quite work since the member is private and can't be accsesed from outside the class. Thankfully the hypothetical class Object provides both, getter and setters for its encapsulated member. However we now need to split serialize into separate save and load functions, thankfully boost allows this too. Unfortunately it seems as if this split is only possible if the user is using the intrusive method. In order to tell boost to split the function the official documentation refers to this macro.
BOOST_SERIALIZATION_SPLIT_MEMBER()
Which translates to:
template<class Archive>
void serialize(Archive &ar, const unsigned int file_version)
{
boost::serialization::split_member(ar, *this, file_version);
}
As you can see, this requires to be placed inside of the class which is exactly what I am trying to avoid in the first place.
Digging around the boost mailing list I have come across this solution:
template <class Archive>
void serialize(Archive & ar, Object& o, const unsigned int version)
{
boost::serialization::split_free(ar, o, version);
}
Now everything seems like it's coming together at last, but my compiler decided differently and printed this error message:
error: no matching function for call to 'load(boost::archive::text_iarchive&, Object&, const boost::serialization::version_type&)'
error: no matching function for call to 'save(boost::archive::text_oarchive&, const Object&, const boost::serialization::version_type&)'
split_free.hpp:45:9: note: cannot convert 't' (type 'const Object') to type 'const boost_132::detail::shared_count&'
What exactly am I doing wrong here?
When you use boost::serialization::split_free()
you have to provide the splitted load()
and save()
methods, that's what the compiler is complaining about.
Using your example and assuming that Member
is the external object that you can't modify, implement the serialisation as follows:
// outside of any namespace
BOOST_SERIALIZATION_SPLIT_FREE(Member)
namespace boost { namespace serialization {
template<class Archive>
void save(Archive& ar, const Member& m, unsigned int) {
...
}
template<class Archive>
void load(Archive& ar, Member& m, unsigned int) {
...
}
}} // namespace boost::serialization
class Object {
private:
Member member;
public:
template<class Archive>
void serialize(Archive& ar, const unsigned int) {
ar & member;
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With