[Serialization] serialize from and to an already instantiated object.

Hello. I've already posted this topic in the boost-user mailing list, but no reply: maybe this boost list is more active... ? Anyway: I use boost.serialization to perform save and load to files. If a class is serializable through the boost mechanism, I'd like to easily add the "savable" feature (through serialization and boost archives). Here how I do, and then I've got 2 questions. I don't post all the #include statements. Let's have a serializable class (I only use text archive for this example) ---------MyClass.h--------- class MyClass { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int version); int data_; public: MyClass(); virtual ~MyClass(); }; BOOST_CLASS_EXPORT_KEY(MyClass) ---------MyClass.cpp--------- MyClass::MyClass() : data_(123) {} MyClass::~MyClass() {} template<class Archive> void MyClass::serialize(Archive & ar, const unsigned int version) { ar & data_; } // instanciate the serialize function for text archives #include "boost/archive/text_iarchive.hpp" #include "boost/archive/text_oarchive.hpp" template void MyClass::serialize(boost::archive::text_iarchive & ar, const unsigned int version); template void MyClass::serialize(boost::archive::text_oarchive & ar, const unsigned int version); BOOST_CLASS_EXPORT_IMPLEMENT(MyClass) --------- Now I define a FileSavable class. Its purpose is to add the "save-to-file" feature to a class that can be serialized in a text archive, making the latter inherting from FileSavable, and adding a line in its serialize function, I write it below). ---------FileSavable.h--------- class FileSavable { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int version); public: virtual ~FileSavable() {} void SaveToFile(std::string path); void LoadFromFile(std::string path); }; BOOST_CLASS_EXPORT_KEY(FileSavable) ---------FileSavable.cpp--------- template<class Archive> void FileSavable::serialize(Archive & ar, const unsigned int version) {} void FileSavable::SaveToFile(std::string path) { std::ofstream ofs(path.c_str()); assert(ofs.good()); boost::archive::text_oarchive oa(ofs); oa & this; } void FileSavable::LoadFromFile(std::string path) { std::ifstream ifs(path.c_str()); assert(ifs.good()); boost::archive::text_iarchive ia(ifs); FileSavable* p; ia & p; *this = *p; delete p; } // instanciate the serialize function for text archives #include "boost/archive/text_iarchive.hpp" #include "boost/archive/text_oarchive.hpp" template void FileSavable::serialize(boost::archive::text_iarchive & ar, const unsigned int version); template void FileSavable::serialize(boost::archive::text_oarchive & ar, const unsigned int version); BOOST_CLASS_EXPORT_IMPLEMENT(FileSavable) ---------Modification to MyClass--------- It now inherit from FileSavable: class MyClass : public FileSavable The serialize function call the base class: template<class Archive> void MyClass::serialize(Archive & ar, const unsigned int version) { ar & boost::serialization::base_object<FileSavable>(*this); ar & data_; } --------- Thanks if you read me until here, now my questions: 1) I don't care the FileSavable part of MyClass being serialized, but if I don't call it with boost::serialization::base_object, I have a runtime error: terminate called after throwing an instance of 'boost::archive::archive_exception' what(): unregistered void cast 7MyClass<-11FileSavable Do you see a way to avoid having to add this line in MyClass? Ideally, just having to inheriting from FileSavable would be great: a simple way to add a feature. 2) As you can see, my LoadFromFile function first creates a new MyClass object in p, by de-serializing an archive, and then copies this newly created object into "*this", and finally deletes the object created by the archive d-eserialization. I didn't find a way to avoid this temporary and de-serialize directly in this. Moreover, my solution is not exception-safe, but I didn't manage to de-serialize in a temporary auto_ptr nor boost::shared_ptr. Thanks in advance for replies. Nicolas.

nico wrote:
Hello.
I've already posted this topic in the boost-user mailing list, but no reply: maybe this boost list is more active... ? Anyway:
I use boost.serialization to perform save and load to files. If a class is serializable through the boost mechanism, I'd like to easily add the "savable" feature (through serialization and boost archives).
I think this is misguided. Including the serialize functions is all you need to make the class "saveable". Adding something besides would be redundent.
Here how I do, and then I've got 2 questions. I don't post all the #include statements.
Let's have a serializable class (I only use text archive for this example)
---------MyClass.h---------
class MyClass { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int version);
int data_;
public: MyClass(); virtual ~MyClass();
};
BOOST_CLASS_EXPORT_KEY(MyClass)
I would not include the above macro unless you know you expect to serialize though a base class pointer.
---------MyClass.cpp---------
MyClass::MyClass() : data_(123) {} MyClass::~MyClass() {}
template<class Archive> void MyClass::serialize(Archive & ar, const unsigned int version) { ar & data_;
}
// instanciate the serialize function for text archives #include "boost/archive/text_iarchive.hpp" #include "boost/archive/text_oarchive.hpp" template void MyClass::serialize(boost::archive::text_iarchive & ar, const unsigned int version); template void MyClass::serialize(boost::archive::text_oarchive & ar, const unsigned int version); BOOST_CLASS_EXPORT_IMPLEMENT(MyClass)
---------
Now I define a FileSavable class. Its purpose is to add the "save-to-file" feature to a class that can be serialized in a text archive, making the latter inherting from FileSavable, and adding a line in its serialize function, I write it below).
---------FileSavable.h---------
class FileSavable { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int version);
public: virtual ~FileSavable() {} void SaveToFile(std::string path); void LoadFromFile(std::string path);
};
BOOST_CLASS_EXPORT_KEY(FileSavable)
---------FileSavable.cpp---------
template<class Archive> void FileSavable::serialize(Archive & ar, const unsigned int version) {}
void FileSavable::SaveToFile(std::string path) { std::ofstream ofs(path.c_str()); assert(ofs.good()); boost::archive::text_oarchive oa(ofs); oa & this;
}
void FileSavable::LoadFromFile(std::string path) { std::ifstream ifs(path.c_str()); assert(ifs.good()); boost::archive::text_iarchive ia(ifs); FileSavable* p; ia & p; *this = *p; delete p;
}
If you REALLY want something like this, consider something like the following: template<class T> void FileSave(const std::string & path, const T & t){ std::ofstream ofs(path.c_str()); boost::archive::text_oarchive oa(ofs); oa << t; } ... then you instead of MyClass t; FileSave(path, t); you would say FileSave(path, t); And if you REALLY want the first syntax you could at the above FileSave template as a member to each serialization class void FileSave(const std::string & path{ std::ofstream ofs(path.c_str()); boost::archive::text_oarchive oa(ofs); oa << *this; } ... I'm not sure what else to say about this. Robert Ramey
// instanciate the serialize function for text archives #include "boost/archive/text_iarchive.hpp" #include "boost/archive/text_oarchive.hpp" template void FileSavable::serialize(boost::archive::text_iarchive & ar, const unsigned int version); template void FileSavable::serialize(boost::archive::text_oarchive & ar, const unsigned int version); BOOST_CLASS_EXPORT_IMPLEMENT(FileSavable)
---------Modification to MyClass--------- It now inherit from FileSavable:
class MyClass : public FileSavable
The serialize function call the base class:
template<class Archive> void MyClass::serialize(Archive & ar, const unsigned int version) { ar & boost::serialization::base_object<FileSavable>(*this); ar & data_;
}
---------
Thanks if you read me until here, now my questions:
1) I don't care the FileSavable part of MyClass being serialized, but if I don't call it with boost::serialization::base_object, I have a runtime error: terminate called after throwing an instance of 'boost::archive::archive_exception' what(): unregistered void cast 7MyClass<-11FileSavable Do you see a way to avoid having to add this line in MyClass? Ideally, just having to inheriting from FileSavable would be great: a simple way to add a feature.
2) As you can see, my LoadFromFile function first creates a new MyClass object in p, by de-serializing an archive, and then copies this newly created object into "*this", and finally deletes the object created by the archive d-eserialization. I didn't find a way to avoid this temporary and de-serialize directly in this. Moreover, my solution is not exception-safe, but I didn't manage to de-serialize in a temporary auto_ptr nor boost::shared_ptr.
Thanks in advance for replies.
Nicolas. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Robert Ramey <ramey <at> rrsd.com> writes:
If you REALLY want something like this, consider something [...] I'm not sure what else to say about this.
Robert Ramey
Thanks for your reply. First: I don't REALLY want my syntax: indeed, provide a "free" function as you suggest is a simple (good) way to add the "savable" feature. One question remains: how to deserialize onto an already instantiated object? Or: how to implement the Load function better than: template<class T> void FileLoad(const std::string & path, T & t){ std::ifstream ifs(path.c_str()); T* p; ia >> p; t = *p; delete p; } which is not exception safe, and not efficient. Nicolas.

Nicolas Guillot wrote:
Robert Ramey <ramey <at> rrsd.com> writes: One question remains: how to deserialize onto an already instantiated object?
serialization is always done into an already instantiated object. For pointers, there is a preliminary step of creating a new object, but after that its the same always. Or: how to implement the Load function better than:
template<class T> void FileLoad(const std::string & path, T & t){ std::ifstream ifs(path.c_str()); T* p; ia >> p; t = *p; delete p; }
use:: template<class T> void FileLoad(const std::string & path, T & t){ std::ifstream ifs(path.c_str()); boost::text_iarchive ia(ifs); ia >> t; } which will run a maximum possible efficiency and will be exception safe. Robert Ramey
participants (3)
-
nico
-
Nicolas Guillot
-
Robert Ramey