/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /** * \file serialization.dox * * Here, we explain what serialization is and how it is used within MoleCuilder. * * Created on: Oct 11, 2011 * Author: heber */ /** \page serialization Serialization * * Serialization is a mighty concept. The is only possible within an object- * oriented framework. The member variables of a class make up its internal * state. By storing this state, creating another instance and restoring * the variables to this state, we may in essence clone the instance. However, * we obtain additional control as to the moment of restoration because the * internal state is stored temporarily. To allow for this storage all of * these variables have to be \e serialized. * * Serialization refers to putting one after another into a writable form * (e.g. convert to string and write into a stringstream) and eventually * in reverse order to read them one by one from this writable form and * cast them back into their original type. * * Here, this is done via boost::serialization. * * \attention The serialization headers do not mingle well with \b MemDebug.hpp. * Hence, place them before MemDebug.hpp as they do funny stuff with the * new() operator. * * Serialization is so powerful because the stored state can be stored to * disk, transfered to another thread or even to another computer. If received * by a compatible code, the instance is recreated and computation can be * continued elsewhere. * * For the moment we use it for creating an undo state within the Action's. * I.e. we store the state of all instances that are modified by an Action's * doings and may in Action::performUndo() just re-create the unmodified * instance by loading them from the serializing archive. * * \section serialization-add How to make your class serializable. * * \subsection serialization-add-simple The simple case * * All you need to do with your newly created class foo is this: * \code * class foo { * ... * private: * friend class boost::serialization::access; * template * void serialize(Archive & ar, const unsigned int version) const * { * ar & content; * } * ... * double content; * }; * \endcode * This will implement a serialization function for both directions for the * member variable content. I.e. we may now store a class instance as this: * \code * #include * std::stringstream stream; * boost::archive::text_oarchive oa(stream); * oa << diagonal; * \endcode * This will store the state of the class in the stringstream \a stream. * Getting the instance back is then as easy as * \code * #include * boost::archive::text_iarchive ia(stream); * RealSpaceMatrix *newm; * ia >> newm; * \endcode * * \subsection serialization-add-complicated The more complicated case * * It gets trickier when load and store need to be done differently, e.h. * \code * class foo { * ... * private: * friend class boost::serialization::access; * // serialization * template * void save(Archive & ar, const unsigned int version) const * { * ar & content; * } * template * void load(Archive & ar, const unsigned int version) * { * ar & content; * createViews(); * } * BOOST_SERIALIZATION_SPLIT_MEMBER() * ... * } * \endcode * Here, we split serialize() function into distinct load() and save() because * we have to call an additional function to fully re-store the instance, i.e. * it creates some internal reference arrays (Views) in a specific manner. * * The serialize functions can also be added externally, i.e. outside of the * scope of the class, but can then access only public members (except we * again make it a friend). * * \subsection serialization-important notes Some important notes * * There are a few things that one needs to be aware of: Otherwise easily * a stupid mistake is introduced that is trivial once understand but hard * to find otherwise. This is especially so because compiler errors with * respect to the serialization part are always length (whole page) and * very hard to read: * \li Always obtain the same type from an archive that you put into it! * If it's been an instance, get an instance, not a ref(&) or a pointer(*) * and also the other way round. * \li boost::serialization always uses the default constructor of your class * that is afterwards filled with state information stored. If your default * constructor is unusable, something goes wrong here. There are two ways * out: * -# Write a private default constructor. Also you might have to split * serialize() into load() and save() and do some additional stuff in * load(). * -# one can write save_construct_data() and load_construct_data() directly * as is explained in the boost::serialization documentation on * constructors (as of 1.47). * \li Const members are a problem as they can only be written during the * constructor and as always the default cstor is used ... however, wiggle * around by casting it to non-const, e.g. * \code * const foo foo_instance; * ... * const_cast(foo_instance); * \endcode * Alternatively, you could place const variables in an extra class (and * non-const there), make them available only via a getter. Hence, they * would still be const in your main class but could be serialized without * any trouble. * \li When you want to serialize a derived class, also the base class state * has to be serialized, this is done via * \code * boost::serialization::base_object(*this); * \endcode * * * \date 2011-11-01 */