931 lines
39 KiB
HTML
931 lines
39 KiB
HTML
<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<!--
|
|
(C) Copyright 2002-4 Robert Ramey - http://www.rrsd.com .
|
|
Use, modification and distribution is subject to the Boost Software
|
|
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
|
http://www.boost.org/LICENSE_1_0.txt)
|
|
-->
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
<link rel="stylesheet" type="text/css" href="style.css">
|
|
<title>Serialization - Serialization of Classes</title>
|
|
</head>
|
|
<body link="#0000ff" vlink="#800080">
|
|
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary="header">
|
|
<tr>
|
|
<td valign="top" width="300">
|
|
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../boost.png" border="0"></a></h3>
|
|
</td>
|
|
<td valign="top">
|
|
<h1 align="center">Serialization</h1>
|
|
<h2 align="center">Serializable Concept</h2>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<hr>
|
|
<dl class="page-index">
|
|
<dt><a href="#primitiveoperators">Primitive Types</a>
|
|
<dt><a href="#classoperators">Class Types</a>
|
|
<dl class="page-index">
|
|
<dt><a href="#member">Member Function</a>
|
|
<dt><a href="#free">Free Function</a>
|
|
<dl class="page-index">
|
|
<dt><a href="#namespaces">Namespaces for Free Function Overrides</a>
|
|
</dl>
|
|
<dt><a href="#classmembers">Class Members</a>
|
|
<dl class="page-index">
|
|
<dt><a href="#base">Base Classes</a>
|
|
<dt><a href="#const"><code style="white-space: normal">const</code> Members</a>
|
|
<dt><a href="#templates">Templates</a>
|
|
</dl>
|
|
<dt><a href="#versioning">Versioning</a>
|
|
<dt><a href="#splitting">Splitting <code style="white-space: normal">serialize</code> into
|
|
<code style="white-space: normal">save/load</code></a>
|
|
<dl class="page-index">
|
|
<dt><a href="#splittingmemberfunctions">Member Functions</a>
|
|
<dt><a href="#splittingfreefunctions">Free Functions</a>
|
|
</dl>
|
|
</dl>
|
|
<dt><a href="#pointeroperators">Pointers</a>
|
|
<dl class="page-index">
|
|
<dt><a href="#constructors">Non-Default Constructors</a>
|
|
<dt><a href="#derivedpointers">Pointers to Objects of Derived Classes</a>
|
|
<dl class="page-index">
|
|
<dt><a href="#registration">Registration</a>
|
|
<dt><a href="#export">Export</a>
|
|
<dt><a href="#instantiation">Instantiation</a>
|
|
<dt><a href="#selectivetracking">Selective Tracking</a>
|
|
<dt><a href="#runtimecasting">Runtime Casting</a>
|
|
</dl>
|
|
</dl>
|
|
<dt><a href="#references">References</a>
|
|
<dt><a href="#arrays">Arrays</a>
|
|
<dt><a href="traits.html">Class Serialization Traits</a>
|
|
<dt><a href="wrappers.html">Serialization Wrappers</a>
|
|
<dt><a href="#models">Models - Serialization Implementations Included in the Library</a>
|
|
</dl>
|
|
|
|
A type <code style="white-space: normal">T</code> is <strong>Serializable</strong>
|
|
if and only if one of the following is true:
|
|
<ul>
|
|
<li>it is a primitive type.<br>
|
|
By <i>primitive type</i> we mean a C++ built-in type and <i>ONLY</i>
|
|
a C++ built-in type. Arithmetic (including characters), bool, enum are primitive types.
|
|
Below in <a target="detail" href="traits.html#Traits">serialization traits</a>,
|
|
we define a "primitive" implementation level in a different way for a
|
|
different purpose. This can be a source of confusion.
|
|
<li>It is a class type and one of the following has been declared according
|
|
to the prototypes detailed below:
|
|
<ul>
|
|
<li>a class member function <code style="white-space: normal">serialize</code>
|
|
<li>a global function <code style="white-space: normal">serialize</code>
|
|
</ul>
|
|
<li>it is a pointer to a <strong>Serializable</strong> type.
|
|
<li>it is a reference to a <strong>Serializable</strong> type.
|
|
<li>it is a native C++ Array of <strong>Serializable</strong> type.
|
|
</ul>
|
|
|
|
<h2><a name="primitiveoperators">Primitive Types</a></h2>
|
|
The template operators &, <<, and >> of the archive classes
|
|
described above will generate code to save/load all primitive types
|
|
to/from an archive. This code will usually just add the
|
|
data to the archive according to the archive format.
|
|
For example, a four byte integer is appended to a binary archive
|
|
as 4 binary bytes while a to a text archive it would be
|
|
rendered as a space followed by a string representation.
|
|
|
|
<h2><a name="classoperators">Class Types</a></h2>
|
|
For class/struct types, the template operators &, <<, and >>
|
|
will generate code that invokes the programmer's serialization code for the
|
|
particular data type. There is no default. An attempt to serialize a
|
|
class/struct for which no serialization has been explicitly specified
|
|
will result in a compile time error. The serialiation of a class can
|
|
be specified via either a class member function or a free funcation which
|
|
takes a reference to an instance of the class as an argument.
|
|
|
|
<h3><a name="member">Member Function</a></h3>
|
|
The serialization library invokes the following code to save or load a class instance
|
|
to/from and archive.
|
|
<pre><code>
|
|
template<class Archive, class T>
|
|
inline void serialize(
|
|
Archive & ar,
|
|
T & t,
|
|
const unsigned int file_version
|
|
){
|
|
// invoke member function for class T
|
|
t.serialize(ar, file_version);
|
|
}
|
|
</code></pre>
|
|
That is, the default definition of template <code style="white-space: normal">serialize</code>
|
|
presumes the existence of a class member function template of the following
|
|
signature:
|
|
<pre><code>
|
|
template<class Archive>
|
|
void serialize(Archive &ar, const unsigned int version){
|
|
...
|
|
}
|
|
</code></pre>
|
|
If such a member function is not declared, a compile time error will occur. In order
|
|
that the member function generated by this template can be called to
|
|
append the data to an archive, it either must be public or the class must
|
|
be made accessible to the serialization library by including:
|
|
<pre><code>
|
|
friend class boost::serialization::access;
|
|
</code></pre>
|
|
in the class definition. This latter method should be preferred over the option
|
|
of making the member function public. This will prevent serialization functions from
|
|
being called from outside the library. This is almost certainly an error. Unfortunately,
|
|
it may appear to function but fail in a way that is very difficult to find.
|
|
<p>
|
|
It may not be immediately obvious how this one template serves for both
|
|
saving data to an archive as well as loading data from the archive.
|
|
The key is that the <code style="white-space: normal">&</code> operator is
|
|
defined as <code style="white-space: normal"><<</code>
|
|
for output archives and as <code style="white-space: normal">>></code> input archives. The
|
|
"polymorphic" behavior of the <code style="white-space: normal">&</code> permits the same template
|
|
to be used for both save and load operations. This is very convenient in that it
|
|
saves a lot of typing and guarantees that the saving and loading of class
|
|
data members are always in sync. This is the key to the whole serialization
|
|
system.
|
|
|
|
<h3><a name="free">Free Function</a></h3>
|
|
Of course we're not restricted to using the default implementation described
|
|
above. We can override the default one with our own. Doing this will
|
|
permit us to implement serialization of a class without altering
|
|
the class definition itself. We call this <strong>non-intrusive</strong>
|
|
serialization. Suppose our class is named <code style="white-space: normal">my_class</code>, the
|
|
override would be specified as:
|
|
<pre><code>
|
|
// namespace selection
|
|
|
|
template<class Archive>
|
|
inline void serialize(
|
|
Archive & ar,
|
|
my_class & t,
|
|
const unsigned int file_version
|
|
){
|
|
...
|
|
}
|
|
</code></pre>
|
|
|
|
Note that we have called this override "non-intrusive". This is slightly
|
|
inaccurate. It does not require that the class have special functions, that
|
|
it be derived from some common base class or any other fundamental design changes.
|
|
However, it will require access to the class members that are to
|
|
be saved and loaded. If these members are <code style="white-space: normal">private</code>, it won't be
|
|
possible to serialize them. So in some instances, minor modifications to the
|
|
class to be serialized will be necessary even when using this "non-intrusive"
|
|
method. In practice this may not be such a problem as many libraries
|
|
(E.G. STL) expose enough information to permit implementation of non-intrusive
|
|
serialization with absolutly no changes to the library.
|
|
|
|
<h4><a name="namespaces">Namespaces for Free Function Overrides</a></h4>
|
|
For maximum portability, include any free functions templates and definitions in the
|
|
namespace <code style="white-space: normal">boost::serialization</code>. If portability is not a concern and the
|
|
compiler being used supports ADL (Argument Dependent Lookup) the free functions and
|
|
templates can be in any of the following namespaces:
|
|
<ul>
|
|
<li><code style="white-space: normal">boost::serialization</code>
|
|
<li>namespace of the archive class
|
|
<li>namespace of the type being serialized
|
|
</ul>
|
|
<p>
|
|
Note that, at first glance, this suggestion may seem to be wrong for compilers which implement
|
|
two phase lookup. In fact, the serialization library used a perhaps overly clever
|
|
method to support this rule even for such compilers. Those with an interest in studying
|
|
this further will find more information in
|
|
<a target=serialization_hpp href="../../../boost/serialization/serialization.hpp">serialization.hpp</a>
|
|
|
|
<h3><a name="classmembers">Serialization of Class Members</a></h3>
|
|
Regardless of which of the above methods is used, the body of the serialize function must
|
|
specify the data to be saved/loaded by sequential application of the archive
|
|
<code style="white-space: normal">operator &</code> to all the data members of the class.
|
|
<pre><code>
|
|
{
|
|
// save/load class member variables
|
|
ar & member1;
|
|
ar & member2;
|
|
}
|
|
</code></pre>
|
|
|
|
<h4><a name="base">Base Classes</a></h4>
|
|
The header file
|
|
<a href="../../../boost/serialization/base_object.hpp" target="base_object_hpp">
|
|
base_object.hpp
|
|
</a>
|
|
includes the template:
|
|
<pre><code>
|
|
template<class Base, class Derived>
|
|
Base & base_object(Derived &d);
|
|
</code></pre>
|
|
which should be used to create a reference to an object of the base
|
|
which can be used as an argument to the archive serialization operators.
|
|
So for a class of <strong>Serializable</strong> type
|
|
<code style="white-space: normal">T</code> the base class state should be
|
|
serialized like this:
|
|
<pre><code>
|
|
{
|
|
// invoke serialization of the base class
|
|
ar & boost::serialization::base_object<base_class_of_T>(*this);
|
|
// save/load class member variables
|
|
ar & member1;
|
|
ar & member2;
|
|
}
|
|
</code></pre>
|
|
Resist the temptation to just cast <code style="white-space: normal">*this</code> to the base class.
|
|
This might seem to work but may fail to invoke code necessary for
|
|
proper serialization.
|
|
<p>
|
|
Note that this is <strong>NOT</strong> the same as calling the <code style="white-space: normal">serialize</code>
|
|
function of the base class. This might seem to work but will circumvent
|
|
certain code used for tracking of objects, and registering base-derived
|
|
relationships and other bookkeeping that is required for the serialization
|
|
system to function as designed. For this reason, all <code style="white-space: normal">serialize</code>
|
|
member functions should be <code style="white-space: normal">private</code>.
|
|
|
|
<h4><a name="const"><code style="white-space: normal">const</code> Members</a></h4>
|
|
Saving <code style="white-space: normal">const</code> members to an archive
|
|
requires no special considerations.
|
|
Loading <code style="white-space: normal">const</code> members can be addressed by using a
|
|
<code style="white-space: normal">const_cast</code>:
|
|
<pre><code>
|
|
ar & const_cast<T &>(t);
|
|
</code></pre>
|
|
Note that this violates the spirit and intention of the <code style="white-space: normal">const</code>
|
|
keyword. <code style="white-space: normal">const</code> members are intialized when a class instance
|
|
is constructed and not changed thereafter. However, this may
|
|
be most appropriate in many cases. Ultimately, it comes down to
|
|
the question about what <code style="white-space: normal">const</code> means in the context
|
|
of serialization.
|
|
|
|
<h4><a name="templates"></a>Templates</h4>
|
|
Implementation of serialization for templates is exactly the same process
|
|
as for normal classes and requires no additional considerations. Among
|
|
other things, this implies that serialization of compositions of templates
|
|
are automatically generated when required if serialization of the
|
|
component templates is defined. For example, this library includes
|
|
definition of serialization for <code style="white-space: normal">boost::shared_ptr<T></code> and for
|
|
<code style="white-space: normal">std::list<T></code>. If I have defined serialization for my own
|
|
class <code style="white-space: normal">my_t</code>, then serialization for
|
|
<code style="white-space: normal">std::list< boost::shared_ptr< my_t> ></code> is already available
|
|
for use.
|
|
<p>
|
|
For an example that shows how this idea might be implemented for your own
|
|
class templates, see
|
|
<a href="../example/demo_auto_ptr.cpp" target="demo_auto_ptr.cpp">
|
|
demo_auto_ptr.cpp</a>.
|
|
This shows how non-intrusive serialization
|
|
for the template <code style="white-space: normal">auto_ptr</code> from the standard library
|
|
can be implemented.
|
|
<p>
|
|
A somewhat trickier addition of serialization to a standard template
|
|
can be found in the example
|
|
<a href="../../../boost/serialization/shared_ptr.hpp" target="shared_ptr_hpp">
|
|
shared_ptr.hpp
|
|
</a>
|
|
<!--
|
|
Only the most minimal change to
|
|
<code>shared_count.hpp</code>
|
|
(to gain access to some private members) was necessary to achieve this.
|
|
This should demonstrate how easy it is to non-intrusively
|
|
implement serialization to any data type or template.
|
|
-->
|
|
<p>
|
|
In the specification of serialization for templates, its common
|
|
to split <code style="white-space: normal">serialize</code>
|
|
into a <code style="white-space: normal">load/save</code> pair.
|
|
Note that the convenience macro described
|
|
<a href="#BOOST_SERIALIZATION_SPLIT_FREE">above</a>
|
|
isn't helpful in these cases as the number and kind of
|
|
template class arguments won't match those used when splitting
|
|
<code style="white-space: normal">serialize</code> for a simple class. Use the override
|
|
syntax instead.
|
|
|
|
<h3><a name="versioning">Versioning</a></h3>
|
|
It will eventually occur that class definitions change after archives have
|
|
been created. When a class instance is saved, the current version
|
|
in included in the class information stored in the archive. When the class instance
|
|
is loaded from the archive, the original version number is passed as an
|
|
argument to the loading function. This permits the load function to include
|
|
logic to accommodate older definitions for the class and reconcile them
|
|
with latest version. Save functions always save the current version. So this
|
|
results in automatically converting older format archives to the newest versions.
|
|
Version numbers are maintained independently for each class. This results in
|
|
a simple system for permitting access to older files and conversion of same.
|
|
The current version of the class is assigned as a
|
|
<a href="traits.html">Class Serialization Trait</a> described later in this manual.
|
|
<pre><code>
|
|
{
|
|
// invoke serialization of the base class
|
|
ar & boost::serialization::base_object<base_class_of_T>(*this);
|
|
// save/load class member variables
|
|
ar & member1;
|
|
ar & member2;
|
|
// if its a recent version of the class
|
|
if(1 < file_version)
|
|
// save load recently added class members
|
|
ar & member3;
|
|
}
|
|
</code></pre>
|
|
|
|
<h3><a name="splitting">Splitting <code style="white-space: normal">serialize</code> into Save/Load</a></h3>
|
|
There are times when it is inconvenient to use the same
|
|
template for both save and load functions. For example, this might occur if versioning
|
|
gets complex.
|
|
|
|
<h4><a name="splittingmemberfunctions">Splitting Member Functions</a></h4>
|
|
For member functions this can be addressed by including
|
|
the header file <a href="../../../boost/serialization/split_member.hpp" target="split_member_hpp">
|
|
boost/serialization/split_member.hpp</a> including code like this in the class:
|
|
<pre><code>
|
|
template<class Archive>
|
|
void save(Archive & ar, const unsigned int version) const
|
|
{
|
|
// invoke serialization of the base class
|
|
ar << boost::serialization::base_object<const base_class_of_T>(*this);
|
|
ar << member1;
|
|
ar << member2;
|
|
ar << member3;
|
|
}
|
|
|
|
template<class Archive>
|
|
void load(Archive & ar, const unsigned int version)
|
|
{
|
|
// invoke serialization of the base class
|
|
ar >> boost::serialization::base_object<base_class_of_T>(*this);
|
|
ar >> member1;
|
|
ar >> member2;
|
|
if(version > 0)
|
|
ar >> member3;
|
|
}
|
|
|
|
template<class Archive>
|
|
void serialize(
|
|
Archive & ar,
|
|
const unsigned int file_version
|
|
){
|
|
boost::serialization::split_member(ar, *this, file_version);
|
|
}
|
|
</code></pre>
|
|
This splits the serialization into two separate functions <code style="white-space: normal">save</code>
|
|
and <code style="white-space: normal">load</code>. Since the new <code style="white-space: normal">serialize</code> template
|
|
is always the same it can be generated by invoking the macro
|
|
BOOST_SERIALIZATION_SPLIT_MEMBER() defined in the header file
|
|
<a href="../../../boost/serialization/split_member.hpp" target="split_member_hpp">
|
|
boost/serialization/split_member.hpp
|
|
</a>.
|
|
So the entire <code style="white-space: normal">serialize</code> function above can be replaced with:
|
|
<pre><code>
|
|
BOOST_SERIALIZATION_SPLIT_MEMBER()
|
|
</code></pre>
|
|
<h4><a name="splittingfreefunctions">Splitting Free Functions</a></h4>
|
|
The situation is same for non-intrusive serialization with the free
|
|
<code style="white-space: normal">serialize</code> function template.
|
|
|
|
<a name="BOOST_SERIALIZATION_SPLIT_FREE">
|
|
To use <code style="white-space: normal">save</code> and
|
|
<code style="white-space: normal">load</code> function templates rather than
|
|
<code style="white-space: normal">serialize</code>:
|
|
<pre><code>
|
|
namespace boost { namespace serialization {
|
|
template<class Archive>
|
|
void save(Archive & ar, const my_class & t, unsigned int version)
|
|
{
|
|
...
|
|
}
|
|
template<class Archive>
|
|
void load(Archive & ar, my_class & t, unsigned int version)
|
|
{
|
|
...
|
|
}
|
|
}}
|
|
</code></pre>
|
|
include the header file
|
|
<a href="../../../boost/serialization/split_free.hpp" target="split_free_hpp">
|
|
boost/serialization/split_free.hpp
|
|
</a>.
|
|
and override the free <code style="white-space: normal">serialize</code> function template:
|
|
<pre><code>
|
|
namespace boost { namespace serialization {
|
|
template<class Archive>
|
|
inline void serialize(
|
|
Archive & ar,
|
|
my_class & t,
|
|
const unsigned int file_version
|
|
){
|
|
split_free(ar, t, file_version);
|
|
}
|
|
}}
|
|
</code></pre>
|
|
To shorten typing, the above template can be replaced with
|
|
the macro:
|
|
<pre><code>
|
|
BOOST_SERIALIZATION_SPLIT_FREE(my_class)
|
|
</code></pre>
|
|
|
|
Note that although the functionality to split the <code style="white-space: normal">
|
|
serialize</code> function into <code style="white-space: normal">save/load</code>
|
|
has been provided, the usage of the <code style="white-space: normal">serialize</code>
|
|
function with the corresponding <code style="white-space: normal">&</code> operator
|
|
is preferred. The key to the serialization implementation is that objects are saved
|
|
and loaded in exactly the same sequence. Using the <code style="white-space: normal">&</code>
|
|
operator and <code style="white-space: normal">serialize</code>
|
|
function guarantees that this is always the case and will minimize the
|
|
occurrence of hard to find errors related to synchronization of
|
|
<code style="white-space: normal">save</code> and <code style="white-space: normal">load</code>
|
|
functions.
|
|
<p>
|
|
Also note that <code style="white-space: normal">BOOST_SERIALIZATION_SPLIT_FREE</code>
|
|
must be used outside of any namespace.
|
|
|
|
<h2><a name="pointeroperators">Pointers</a></h2>
|
|
A pointer to any class instance can be serialized with any of the archive
|
|
save/load operators.
|
|
<p>
|
|
To properly save and restore an object through a pointer the
|
|
following situations must be addressed:
|
|
<ol>
|
|
<li>If the same object is saved multiple times through different
|
|
pointers, only one copy of the object need be saved.
|
|
<li>If an object is loaded multiple times through different pointers,
|
|
only one new object should be created and all returned pointers
|
|
should point to it.
|
|
<li>The system must detect the case where an object is first
|
|
saved through a pointer then the object itself is saved.
|
|
Without taking extra precautions, loading would result in the
|
|
creation of multiple copies of the original object. This system detects
|
|
this case when saving and throws an exception - see below.
|
|
<li>An object of a derived class may be stored through a
|
|
pointer to the base class. The true type of the object must
|
|
be determined and saved. Upon restoration the correct type
|
|
must be created and its address correctly cast to the base
|
|
class. That is, polymorphic pointers have to be considered.
|
|
<li>NULL pointers must be dectected when saved and restored
|
|
to NULL when deserialized.
|
|
</ol>
|
|
|
|
This serialization library addresses all of the above
|
|
considerations. The process of saving and loading an object
|
|
through a pointer is non-trivial. It can be summarized as
|
|
follows:
|
|
<p>Saving a pointer:
|
|
<ol>
|
|
<li>determine the true type of the object being pointed to.
|
|
<li>write a special tag to the archive
|
|
<li>if the object pointed to has not already been written
|
|
to the archive, do so now
|
|
</ol>
|
|
Loading a pointer:
|
|
<ol>
|
|
<li>read a tag from the archive.
|
|
<li>determine the type of object to be created
|
|
<li>if the object has already been loaded, return its address.
|
|
<li>otherwise, create a new instance of the object
|
|
<li>read the data back in using the operators described above
|
|
<li>return the address of the newly created object.
|
|
</ol>
|
|
|
|
Given that class instances are saved/loaded to/from the archive
|
|
only once, regardless of how many times they are serialized with
|
|
the <code style="white-space: normal"><<</code>
|
|
and <code style="white-space: normal">>></code> operators
|
|
<ul>
|
|
<li>Loading the same pointer object multiple times
|
|
results in only one object being created, thereby replicating
|
|
the original pointer configuration.
|
|
<li>Structures, such as collections of polymorphic pointers,
|
|
are handled with no special effort on the part of users of this library.
|
|
</ul>
|
|
Serialization of pointers of derived types through a pointer to the
|
|
base class may require a little extra "help". Also, the programmer
|
|
may desire to modify the process described above for his own reasons.
|
|
For example, it might be desired to suppress the tracking of objects
|
|
as it is known a priori that the application in question can never
|
|
create duplicate objects. Serialization of pointers can be "fine tuned"
|
|
via the specification of <a target="detail" href="traits.html#Traits">Class Serialization Traits</a>
|
|
as described in
|
|
<a target="detail" href="special.html#derivedpointers">
|
|
another section of this manual
|
|
</a>
|
|
|
|
<h3><a name="constructors">Non-Default Constructors</a></h3>
|
|
Serialization of pointers is implemented in the library with code
|
|
similar to the following:
|
|
<pre><code>
|
|
// load data required for construction and invoke constructor in place
|
|
template<class Archive, class T>
|
|
inline void load_construct_data(
|
|
Archive & ar, T * t, const unsigned int file_version
|
|
){
|
|
// default just uses the default constructor to initialize
|
|
// previously allocated memory.
|
|
::new(t)T();
|
|
}
|
|
</code></pre>
|
|
The default <code style="white-space: normal">load_construct_data</code> invokes the
|
|
default constructor "in-place" to initialize the memory.
|
|
<p>
|
|
If there is no such default constructor, the function templates
|
|
<code style="white-space: normal">load_construct_data</code> and
|
|
perhaps <code style="white-space: normal">save_construct_data</code>
|
|
will have to be overridden. Here is a simple example:
|
|
<pre><code>
|
|
class my_class {
|
|
private:
|
|
friend class boost::serialization::access;
|
|
const int m_attribute; // some immutable aspect of the instance
|
|
int m_state; // mutable state of this instance
|
|
template<class Archive>
|
|
void serialize(Archive &ar, const unsigned int file_version){
|
|
ar & m_state;
|
|
}
|
|
public:
|
|
// no default construct guarentees that no invalid object
|
|
// ever exists
|
|
my_class(int attribute) :
|
|
m_attribute(attribute),
|
|
m_state(0)
|
|
{}
|
|
};
|
|
</code></pre>
|
|
the overrides would be:
|
|
<pre><code>
|
|
namespace boost { namespace serialization {
|
|
template<class Archive>
|
|
inline void save_construct_data(
|
|
Archive & ar, const my_class * t, const unsigned int file_version
|
|
){
|
|
// save data required to construct instance
|
|
ar << t->m_attribute;
|
|
}
|
|
|
|
template<class Archive>
|
|
inline void load_construct_data(
|
|
Archive & ar, my_class * t, const unsigned int file_version
|
|
){
|
|
// retrieve data from archive required to construct new instance
|
|
int attribute;
|
|
ar >> attribute;
|
|
// invoke inplace constructor to initialize instance of my_class
|
|
::new(t)my_class(attribute);
|
|
}
|
|
}} // namespace ...
|
|
</code></pre>
|
|
In addition to the deserialization of pointers, these overrides are used
|
|
in the deserialization of STL containers whose element type has no default
|
|
constructor.
|
|
|
|
<h3><a name="derivedpointers">Pointers to Objects of Derived Classes</a></h3>
|
|
<h4><a name="registration">Registration</a></h4>
|
|
Consider the following:
|
|
<pre><code>
|
|
class base {
|
|
...
|
|
};
|
|
class derived_one : public base {
|
|
...
|
|
};
|
|
class derived_two : public base {
|
|
...
|
|
};
|
|
main(){
|
|
...
|
|
base *b;
|
|
...
|
|
ar & b;
|
|
}
|
|
</code></pre>
|
|
When saving <code style="white-space: normal">b</code> what kind of object should be saved?
|
|
When loading <code style="white-space: normal">b</code> what kind of object should be created?
|
|
Should it be an object of class <code style="white-space: normal">derived_one</code>,
|
|
<code style="white-space: normal">derived_two</code>, or maybe <code style="white-space: normal">base</code>?
|
|
<p>
|
|
It turns out that the kind of object serialized depends upon whether the base class
|
|
(<code style="white-space: normal">base</code> in this case) is polymophic or not.
|
|
If <code style="white-space: normal">base</code> is not polymorphic, that is if it has no
|
|
virtual functions, then an object of the type <code style="white-space: normal">base</code>
|
|
will be serialized. Information in any derived classes will be lost. If this is what is desired
|
|
(it usually isn't) then no other effort is required.
|
|
<p>
|
|
|
|
If the base class is polymorphic, an object of the most derived type
|
|
(<code style="white-space: normal">derived_one</code>
|
|
or <code style="white-space: normal">derived_two</code>
|
|
in this case) will be serialized. The question of which type of object is to be
|
|
serialized is (almost) automatically handled by the library.
|
|
<p>
|
|
The system "registers" each class in an archive the first time an object of that
|
|
class it is serialized and assigns a sequential number to it. Next time an
|
|
object of that class is serialized in that same archive, this number is written
|
|
in the archive. So every class is identified uniquely within the archive.
|
|
When the archive is read back in, each new sequence number is re-associated with
|
|
the class being read. Note that this implies that "registration" has to occur
|
|
during both save and load so that the class-integer table built on load
|
|
is identical to the class-integer table built on save. In fact, the key to
|
|
whole serialization system is that things are always saved and loaded in
|
|
the same sequence. This includes "registration".
|
|
<p>
|
|
Expanding our previous example:
|
|
<pre><code>
|
|
main(){
|
|
derived_one d1;
|
|
derived_two d2:
|
|
...
|
|
ar & d1;
|
|
ar & d2;
|
|
// A side effect of serialization of objects d1 and d2 is that
|
|
// the classes derived_one and derived_two become known to the archive.
|
|
// So subsequent serialization of those classes by base pointer works
|
|
// without any special considerations.
|
|
base *b;
|
|
...
|
|
ar & b;
|
|
}
|
|
</code></pre>
|
|
When <code style="white-space: normal">b</code> is read it is
|
|
preceded by a unique (to the archive) class identifier which
|
|
has previously been related to class <code style="white-space: normal">derived_one</code> or
|
|
<code style="white-space: normal">derived_two</code>.
|
|
<p>
|
|
If a derived class has NOT been automatically "registered" as described
|
|
above, an <a target="detail" href="exceptions.html#unregistered_class">
|
|
<code style="white-space: normal">unregistered_class</code></a> exception
|
|
will be thrown when serialization is invoked.
|
|
<p>
|
|
This can be addressed by registering the derived class explicitly. All archives are
|
|
derived from a base class which implements the following template:
|
|
<pre><code>
|
|
template<class T>
|
|
register_type();
|
|
</code></pre>
|
|
So our problem could just as well be addressed by writing:
|
|
<pre><code>
|
|
main(){
|
|
...
|
|
ar.template register_type<derived_one>();
|
|
ar.template register_type<derived_two>();
|
|
base *b;
|
|
...
|
|
ar & b;
|
|
}
|
|
</code></pre>
|
|
Note that if the serialization function is split between save and load, both
|
|
functions must include the registration. This is required to keep the save
|
|
and corresponding load in syncronization.
|
|
|
|
<h4><a name="export">Export</a></h4>
|
|
The above will work but may be inconvenient. We don't always know which derived
|
|
classes we are going to serialize when we write the code to serialize through
|
|
a base class pointer. Every time a new derived class is written we have to
|
|
go back to all the places where the base class is serialized and update the
|
|
code.
|
|
<p>
|
|
So we have another method:
|
|
<pre><code>
|
|
#include <boost/serialization/export.hpp>
|
|
...
|
|
BOOST_CLASS_EXPORT_GUID(derived_one, "derived_one")
|
|
BOOST_CLASS_EXPORT_GUID(derived_two, "derived_two")
|
|
|
|
main(){
|
|
...
|
|
base *b;
|
|
...
|
|
ar & b;
|
|
}
|
|
</code></pre>
|
|
The macro <code style="white-space: normal">BOOST_CLASS_EXPORT_GUID</code> associates a string literal
|
|
with a class. In the above example we've used a string rendering
|
|
of the class name. If a object of such an "exported" class is serialized
|
|
through a pointer and is otherwise unregistered, the "export" string is
|
|
included in the archive. When the archive
|
|
is later read, the string literal is used to find the class which
|
|
should be created by the serialization library.
|
|
This permits each class to be in a separate header file along with its
|
|
string identifier. There is no need to maintain a separate "pre-registration"
|
|
of derived classes that might be serialized. This method of
|
|
registration is referred to as "key export". More information on this
|
|
topic is found in the section Class Traits -
|
|
<a target="detail" href="traits.html#export">Export Key</a>.
|
|
<p>
|
|
<h4><a name="instantiation">Instantiation</a></h4>
|
|
Registration by means of any of the above methods fulfill another role
|
|
whose importance might not be obvious. This system relies on templated
|
|
functions of the form <code style="white-space: normal">template<class Archive, class T></code>.
|
|
This means that serialization code must be instantiated for each
|
|
combination of archive and data type that is serialized in the program.
|
|
<p>
|
|
Polymorphic pointers of derived classes may never be referred to
|
|
explictly by the program so normally code to serialize such classes
|
|
would never be instantiated. So in addition to including export key
|
|
strings in an archive, <code style="white-space: normal">BOOST_CLASS_EXPORT_GUID</code> explicitly
|
|
instantiates the class serialization code for all archive classes used
|
|
by the program.
|
|
|
|
<h4><a name="selectivetracking">Selective Tracking</a></h4>
|
|
Whether or not an object is tracked is determined by its
|
|
<a target="detail" href="traits.html#tracking">object tracking trait</a>.
|
|
The default setting for user defined types is <code style="white-space: normal">track_selectively</code>.
|
|
That is, track objects if and only if they are serialized through pointers anywhere
|
|
in the program. Any objects that are "registered" by any of the above means are presumed
|
|
to be serialized through pointers somewhere in the program and therefore
|
|
would be tracked. In certain situations this could lead to an inefficiency.
|
|
Suppose we have a class module used by multiple programs. Because
|
|
some programs serializes polymorphic pointers to objects of this class, we
|
|
<a target="detail" href="traits.html#export">export</a> a class
|
|
identifier by specifying <code style="white-space: normal">BOOST_CLASS_EXPORT</code> in the
|
|
class header. When this module is included by another program,
|
|
objects of this class will always be tracked even though it
|
|
may not be necessary. This situation could be addressed by using
|
|
<a target="detail" href="traits.html#tracking"><code style="white-space: normal">track_never</code></a>
|
|
in those programs.
|
|
<p>
|
|
It could also occur that even though a program serializes through
|
|
a pointer, we are more concerned with efficiency than avoiding the
|
|
the possibility of creating duplicate objects. It could be
|
|
that we happen to know that there will be no duplicates. It could
|
|
also be that the creation of a few duplicates is benign and not
|
|
worth avoiding given the runtime cost of tracking duplicates.
|
|
Again, <a target="detail" href="traits.html#tracking"><code style="white-space: normal">track_never</code></a>
|
|
can be used.
|
|
<h4><a name="runtimecasting">Runtime Casting</a></h4>
|
|
In order to properly translate between base and derived pointers
|
|
at runtime, the system requires each base/derived pair be found
|
|
in a table. A side effect of serializing a base object with
|
|
<code style="white-space: normal">boost::serialization::base_object<Base>(Derived &)</code>
|
|
is to ensure that the base/derived pair is added to the table
|
|
before the <code style="white-space: normal">main</code> function is entered.
|
|
This is very convenient and results in a clean syntax. The only
|
|
problem is that it can occur where a derived class serialized
|
|
through a pointer has no need to invoke the serialization of
|
|
its base class. In such a case, there are two choices. The obvious
|
|
one is to invoke the base class serialization with <code style="white-space: normal">base_object</code>
|
|
and specify an empty function for the base class serialization.
|
|
The alternative is to "register" the Base/Derived relationship
|
|
explicitly by invoking the template
|
|
<code style="white-space: normal">void_cast_register<Derived, Base>();</code>.
|
|
Note that this usage of the term "register" is not related
|
|
to its usage in the previous section. Here is an example of how this is done:
|
|
<pre><code>
|
|
#include <sstream>
|
|
#include <boost/serialization/serialization.hpp>
|
|
#include <boost/archive/text_iarchive.hpp>
|
|
#include <boost/serialization/export.hpp>
|
|
|
|
class base {
|
|
friend class boost::serialization::access;
|
|
//...
|
|
// only required when using method 1 below
|
|
// no real serialization required - specify a vestigial one
|
|
template<class Archive>
|
|
void serialize(Archive & ar, const unsigned int file_version){}
|
|
};
|
|
|
|
class derived : public base {
|
|
friend class boost::serialization::access;
|
|
template<class Archive>
|
|
void serialize(Archive & ar, const unsigned int file_version){
|
|
// method 1 : invoke base class serialization
|
|
ar & boost::serialization::base_object<base>(*this);
|
|
// method 2 : explicitly register base/derived relationship
|
|
boost::serialization::void_cast_register<derived, base>(
|
|
static_cast<derived *>(NULL),
|
|
static_cast<base *>(NULL)
|
|
)
|
|
}
|
|
};
|
|
|
|
BOOST_CLASS_EXPORT_GUID(derived, "derived")
|
|
|
|
main(){
|
|
//...
|
|
std::stringstream ss;
|
|
boost::archive::text_iarchive ar(ss);
|
|
base *b;
|
|
ar >> b;
|
|
}
|
|
</code></pre>
|
|
<p>
|
|
|
|
In order for this template to be invoked in code compiled by non-conforming
|
|
compilers, the following syntax may be used:
|
|
<pre><code>
|
|
boost::serialization::void_cast_register(
|
|
static_cast<Derived *>(NULL),
|
|
static_cast<Base *>(NULL)
|
|
);
|
|
</code></pre>
|
|
For more information, see <a target="detail" href="implementation.html#tempatesyntax">Template Invocation syntax</a>
|
|
|
|
<h3><a name="references"></a>References</h3>
|
|
Classes that contain reference members will generally require
|
|
non-default constructors as references can only be set when
|
|
an instance is constructed. The example of the previous section
|
|
is slightly more complex if the class has reference members.
|
|
This raises the question of how and where the objects being
|
|
referred to are stored and how are they created. Also there is the question about
|
|
references to polymorphic base classes. Basically, these
|
|
are the same questions that arise regarding pointers. This is
|
|
no surprise as references are really a special kind of pointer.
|
|
We address these questions by serializing references as though
|
|
they were pointers.
|
|
<pre><code>
|
|
class object;
|
|
class my_class {
|
|
private:
|
|
friend class boost::serialization::access;
|
|
int member1;
|
|
object & member2;
|
|
template<class Archive>
|
|
void serialize(Archive &ar, const unsigned int file_version);
|
|
public:
|
|
my_class(int m, object & o) :
|
|
member1(m),
|
|
member2(o)
|
|
{}
|
|
};
|
|
</code></pre>
|
|
the overrides would be:
|
|
<pre><code>
|
|
namespace boost { namespace serialization {
|
|
template<class Archive>
|
|
inline void save_construct_data(
|
|
Archive & ar, const my_class * t, const unsigned int file_version
|
|
){
|
|
// save data required to construct instance
|
|
ar << t.member1;
|
|
// serialize reference to object as a pointer
|
|
ar << & t.member2;
|
|
}
|
|
|
|
template<class Archive>
|
|
inline void load_construct_data(
|
|
Archive & ar, my_class * t, const unsigned int file_version
|
|
){
|
|
// retrieve data from archive required to construct new instance
|
|
int m;
|
|
ar >> m;
|
|
// create and load data through pointer to object
|
|
// tracking handles issues of duplicates.
|
|
object * optr;
|
|
ar >> optr;
|
|
// invoke inplace constructor to initialize instance of my_class
|
|
::new(t)my_class(m, *optr);
|
|
}
|
|
}} // namespace ...
|
|
</code></pre>
|
|
|
|
<h3><a name="arrays"></a>Arrays</h3>
|
|
If <code style="white-space: normal">T</code> is a serializable type,
|
|
then any native C++ array of type T is a serializable type.
|
|
That is, if <code style="white-space: normal">T</code>
|
|
is a serializable type, then the following
|
|
is automatically available and will function as expected:
|
|
<pre><code>
|
|
T t[4];
|
|
ar << t;
|
|
...
|
|
ar >> t;
|
|
</code></pre>
|
|
|
|
<h2><a href="traits.html">Class Serialization Traits</a></h2>
|
|
|
|
<h2><a href="wrappers.html">Serialization Wrappers</a></h2>
|
|
|
|
<h2><a name="models"></a>Models - Serialization Implementations Included in the Library</h2>
|
|
The facilities described above are sufficient to implement
|
|
serialization for all STL containers. In fact, this has been done
|
|
and has been included in the library. For example, in order to use
|
|
the included serialization code for <code style="white-space: normal">std::list</code>, use:
|
|
<pre><code>
|
|
#include <boost/serialization/list.hpp>
|
|
</code></pre>
|
|
rather than
|
|
<pre><code>
|
|
#include <list>
|
|
</code></pre>
|
|
Since the former includes the latter, this is all that is necessary.
|
|
The same holds true for all STL collections as well as templates
|
|
required to support them (e.g. <code style="white-space: normal">std::pair</code>).
|
|
<p>
|
|
As of this writing, the library contains serialization of the following boost classes:
|
|
<ul>
|
|
<li>optional
|
|
<li>variant
|
|
<li>scoped_ptr
|
|
<li>shared_ptr
|
|
<li>auto_ptr (demo)
|
|
</ul>
|
|
Others are being added to the list so check the boost files section and headers for
|
|
new implementations!
|
|
<hr>
|
|
<p><i>© Copyright <a href="http://www.rrsd.com">Robert Ramey</a> 2002-2004.
|
|
Distributed under the Boost Software License, Version 1.0. (See
|
|
accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
</i></p>
|
|
</body>
|
|
</html>
|