1 | <!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
---|
2 | <html> |
---|
3 | <!-- |
---|
4 | (C) Copyright 2002-4 Robert Ramey - http://www.rrsd.com . |
---|
5 | Use, modification and distribution is subject to the Boost Software |
---|
6 | License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
---|
7 | http://www.boost.org/LICENSE_1_0.txt) |
---|
8 | --> |
---|
9 | <head> |
---|
10 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
---|
11 | <link rel="stylesheet" type="text/css" href="../../../boost.css"> |
---|
12 | <link rel="stylesheet" type="text/css" href="style.css"> |
---|
13 | <title>Serialization - Serialization of Classes</title> |
---|
14 | </head> |
---|
15 | <body link="#0000ff" vlink="#800080"> |
---|
16 | <table border="0" cellpadding="7" cellspacing="0" width="100%" summary="header"> |
---|
17 | <tr> |
---|
18 | <td valign="top" width="300"> |
---|
19 | <h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../boost.png" border="0"></a></h3> |
---|
20 | </td> |
---|
21 | <td valign="top"> |
---|
22 | <h1 align="center">Serialization</h1> |
---|
23 | <h2 align="center">Serializable Concept</h2> |
---|
24 | </td> |
---|
25 | </tr> |
---|
26 | </table> |
---|
27 | <hr> |
---|
28 | <dl class="page-index"> |
---|
29 | <dt><a href="#primitiveoperators">Primitive Types</a> |
---|
30 | <dt><a href="#classoperators">Class Types</a> |
---|
31 | <dl class="page-index"> |
---|
32 | <dt><a href="#member">Member Function</a> |
---|
33 | <dt><a href="#free">Free Function</a> |
---|
34 | <dl class="page-index"> |
---|
35 | <dt><a href="#namespaces">Namespaces for Free Function Overrides</a> |
---|
36 | </dl> |
---|
37 | <dt><a href="#classmembers">Class Members</a> |
---|
38 | <dl class="page-index"> |
---|
39 | <dt><a href="#base">Base Classes</a> |
---|
40 | <dt><a href="#const"><code style="white-space: normal">const</code> Members</a> |
---|
41 | <dt><a href="#templates">Templates</a> |
---|
42 | </dl> |
---|
43 | <dt><a href="#versioning">Versioning</a> |
---|
44 | <dt><a href="#splitting">Splitting <code style="white-space: normal">serialize</code> into |
---|
45 | <code style="white-space: normal">save/load</code></a> |
---|
46 | <dl class="page-index"> |
---|
47 | <dt><a href="#splittingmemberfunctions">Member Functions</a> |
---|
48 | <dt><a href="#splittingfreefunctions">Free Functions</a> |
---|
49 | </dl> |
---|
50 | </dl> |
---|
51 | <dt><a href="#pointers">Pointers</a> |
---|
52 | <dl class="page-index"> |
---|
53 | <dt><a href="#constructors">Non-Default Constructors</a> |
---|
54 | <dt><a href="#derivedpointers">Pointers to Objects of Derived Classes</a> |
---|
55 | <dl class="page-index"> |
---|
56 | <dt><a href="#registration">Registration</a> |
---|
57 | <dt><a href="#instantiation">Instantiation</a> |
---|
58 | <dt><a href="#selectivetracking">Selective Tracking</a> |
---|
59 | <dt><a href="#runtimecasting">Runtime Casting</a> |
---|
60 | </dl> |
---|
61 | </dl> |
---|
62 | <dt><a href="#references">References</a> |
---|
63 | <dt><a href="#arrays">Arrays</a> |
---|
64 | <dt><a href="wrappers.html">Serialization Wrappers</a> |
---|
65 | <dt><a href="traits.html">Class Serialization Traits</a> |
---|
66 | <dt><a href="#models">Models - Serialization Implementations Included in the Library</a> |
---|
67 | </dl> |
---|
68 | |
---|
69 | A type <code style="white-space: normal">T</code> is <strong>Serializable</strong> |
---|
70 | if and only if one of the following is true: |
---|
71 | <ul> |
---|
72 | <li>it is a primitive type.<br> |
---|
73 | In this document, we use the term primitive type to mean |
---|
74 | types whose data is simply saved/loaded to/from an archive |
---|
75 | with no further processing. Arithmetic (including characters), |
---|
76 | bool, enum and stl::string and stl::wstring types are primitive types. Using |
---|
77 | <a target="detail" href="traits.html#Traits">serialization traits</a>, |
---|
78 | any user type can also be designated as "primitive" |
---|
79 | so that it is handled in this way. |
---|
80 | <li>It is a class type and one of the following has been declared: |
---|
81 | <ul> |
---|
82 | <li>a class member function <code style="white-space: normal">serialize</code> |
---|
83 | <li>a global function <code style="white-space: normal">serialize</code> |
---|
84 | </ul> |
---|
85 | <li>it is a pointer to a <strong>Serializable</strong> type. |
---|
86 | <li>it is a reference to a <strong>Serializable</strong> type. |
---|
87 | <li>it is an native C++ Array of <strong>Serializable</strong> type. |
---|
88 | </ul> |
---|
89 | |
---|
90 | <h2><a name="primitiveoperators">Primitive Types</a></h2> |
---|
91 | The template operators &, <<, and >> of the archive classes |
---|
92 | described above will generate code to save/load all primitive types |
---|
93 | to/from an archive. This code will usually just add the |
---|
94 | data to the archive according to the archive format. |
---|
95 | For example, a four byte integer is appended to a binary archive |
---|
96 | as 4 binary bytes while a to a text archive it would be |
---|
97 | rendered as a space followed by a string representation. |
---|
98 | |
---|
99 | <h2><a name="classoperators">Class Types</a></h2> |
---|
100 | For class/struct types, the template operators &, <<, and >> |
---|
101 | will generate code that invokes the programmer's serialization code for the |
---|
102 | particular data type. There is no default. An attempt to serialize a |
---|
103 | class/struct for which no serialization has been explicitly specified |
---|
104 | will result in a compile time error. The serialiation of a class can |
---|
105 | be specified via either a class member function or a free funcation which |
---|
106 | takes a reference to an instance of the class as an argument. |
---|
107 | |
---|
108 | <h3><a name="member">Member Function</a></h3> |
---|
109 | The serialization library invokes the following code to save or load a class instance |
---|
110 | to/from and archive. |
---|
111 | <pre><code> |
---|
112 | template<class Archive, class T> |
---|
113 | inline void serialize( |
---|
114 | Archive & ar, |
---|
115 | T & t, |
---|
116 | const unsigned int file_version |
---|
117 | ){ |
---|
118 | // invoke member function for class T |
---|
119 | t.serialize(ar, file_version); |
---|
120 | } |
---|
121 | </code></pre> |
---|
122 | That is, the default definition of template <code style="white-space: normal">serialize</code> |
---|
123 | presumes the existence of a class member function template of the following |
---|
124 | signature: |
---|
125 | <pre><code> |
---|
126 | template<class Archive> |
---|
127 | void serialize(Archive &ar, const unsigned int version){ |
---|
128 | ... |
---|
129 | } |
---|
130 | </code></pre> |
---|
131 | If such a member function is not declared, a compile time error will occur. In order |
---|
132 | that the member function generated by this template can be called to |
---|
133 | append the data to an archive, it either must be public or the class must |
---|
134 | be made accessible to the serialization library by including: |
---|
135 | <pre><code> |
---|
136 | friend class boost::serialization::access; |
---|
137 | </code></pre> |
---|
138 | in the class definition. This latter method should be preferred over the option |
---|
139 | of making member function public. This will prevent serialization functions from |
---|
140 | being called from outside the library. This is almost certainly an error. Unfortunately, |
---|
141 | it may appear to function but fail in a way that is very difficult to find. |
---|
142 | <p> |
---|
143 | It may not be immediately obvious how this one template serves for both |
---|
144 | saving data to an archive as well as loading data from the archive. |
---|
145 | The key is that the <code style="white-space: normal">&</code> operator is |
---|
146 | defined as <code style="white-space: normal"><<</code> |
---|
147 | for output archives and as <code style="white-space: normal">>></code> input archives. The |
---|
148 | "polymorphic" behavior of the <code style="white-space: normal">&</code> permits the same template |
---|
149 | to be used for both save and load operations. This is very convenient in that it |
---|
150 | saves a lot of typing and guarantees that the saving and loading of class |
---|
151 | data members are always in sync. This is the key to the whole serialization |
---|
152 | system. |
---|
153 | |
---|
154 | <h3><a name="free">Free Function</a></h3> |
---|
155 | Of course we're not restricted to using the default implementation described |
---|
156 | above. We can override the default one with our own. Doing this will |
---|
157 | permit us to implement serialization of a class without altering |
---|
158 | the class definition itself. We call this <strong>non-intrusive</strong> |
---|
159 | serialization. Suppose our class is named <code style="white-space: normal">my_class</code>, the |
---|
160 | override would be specified as: |
---|
161 | <pre><code> |
---|
162 | // namespace selection |
---|
163 | |
---|
164 | template<class Archive> |
---|
165 | inline void serialize( |
---|
166 | Archive & ar, |
---|
167 | my_class & t, |
---|
168 | const unsigned int file_version |
---|
169 | ){ |
---|
170 | ... |
---|
171 | } |
---|
172 | </code></pre> |
---|
173 | |
---|
174 | Note that we have called this override "non-intrusive". This is slightly |
---|
175 | inaccurate. It does not require that the class have special functions, that |
---|
176 | it be derived from some common base class or any other fundamental design changes. |
---|
177 | However, it will require access to the class members that are to |
---|
178 | be saved and loaded. If these members are <code style="white-space: normal">private</code>, it won't be |
---|
179 | possible to serialize them. So in some instances, minor modifications to the |
---|
180 | class to be serialized will be necessary even when using this "non-intrusive" |
---|
181 | method. In practice this may not be such a problem as many libraries |
---|
182 | (E.G. STL) expose enough information to permit implementation of non-intrusive |
---|
183 | serialization with absolutly no changes to the library. |
---|
184 | |
---|
185 | <h4><a name="namespaces">Namespaces for Free Function Overrides</a></h4> |
---|
186 | For maximum portability, include any free functions templates and definitions in the |
---|
187 | namespace <code style="white-space: normal">boost::serialization</code>. If portability is not a concern and the |
---|
188 | compiler being used supports ADL (Argument Dependent Lookup) the free functions and |
---|
189 | templates can be in any of the following namespaces: |
---|
190 | <ul> |
---|
191 | <li><code style="white-space: normal">boost::serialization</code> |
---|
192 | <li>namespace of the archive class |
---|
193 | <li>namespace of the type being serialized |
---|
194 | </ul> |
---|
195 | <p> |
---|
196 | Note that, at first glance, this suggestion may seem to be wrong for compilers which implement |
---|
197 | two phase lookup. In fact, the serialization library used a perhaps overly clever |
---|
198 | method to support this rule even for such compilers. Those with an interest in studying |
---|
199 | this furter will find more information in |
---|
200 | <a target=serialization_hpp href="../../../boost/serialization/serialization.hpp">serialization.hpp</a> |
---|
201 | |
---|
202 | <h3><a name="classmembers">Serialization of Class Members</a></h3> |
---|
203 | Regardless of which of the above methods is used, the body of the serialize function must |
---|
204 | specify the data to be saved/loaded by sequential application of the archive |
---|
205 | <code style="white-space: normal">operator &</code> to all the data members of the class. |
---|
206 | <pre><code> |
---|
207 | { |
---|
208 | // save/load class member variables |
---|
209 | ar & member1; |
---|
210 | ar & member2; |
---|
211 | } |
---|
212 | </code></pre> |
---|
213 | |
---|
214 | <h4><a name="base">Base Classes</a></h4> |
---|
215 | The header file |
---|
216 | <a href="../../../boost/serialization/base_object.hpp" target="base_object_hpp"> |
---|
217 | base_object.hpp |
---|
218 | </a> |
---|
219 | includes the template: |
---|
220 | <pre><code> |
---|
221 | template<class Base, class Derived> |
---|
222 | Base & base_object(Derived &d); |
---|
223 | </code></pre> |
---|
224 | which should be used to create a reference to an object of the base |
---|
225 | which can be used as an argument to the archive serialization operators. |
---|
226 | So for a class of <strong>Serializable</strong> type |
---|
227 | <code style="white-space: normal">T</code> the base class state should be |
---|
228 | serialized like this: |
---|
229 | <pre><code> |
---|
230 | { |
---|
231 | // invoke serialization of the base class |
---|
232 | ar & boost::serialization::base_object<base_class_of_T>(*this); |
---|
233 | // save/load class member variables |
---|
234 | ar & member1; |
---|
235 | ar & member2; |
---|
236 | } |
---|
237 | </code></pre> |
---|
238 | Resist the temptation to just cast <code style="white-space: normal">*this</code> to the base class. |
---|
239 | This might seem to work but may fail to invoke code necessary for |
---|
240 | proper serialization. |
---|
241 | <p> |
---|
242 | Note that this is <strong>NOT</strong> the same as calling the <code style="white-space: normal">serialize</code> |
---|
243 | function of the base class. This might seem to work but will circumvent |
---|
244 | certain code used for tracking of objects, and registering base-derived |
---|
245 | relationships and other bookkeeping that is required for the serialization |
---|
246 | system to function as designed. For this reason, all <code style="white-space: normal">serialize</code> |
---|
247 | member functions should be <code style="white-space: normal">private</code>. |
---|
248 | |
---|
249 | <h4><a name="const"><code style="white-space: normal">const</code> Members</a></h4> |
---|
250 | Saving <code style="white-space: normal">const</code> members to an archive |
---|
251 | requires no special considerations. |
---|
252 | Loading <code style="white-space: normal">const</code> members can be addressed by using a |
---|
253 | <code style="white-space: normal">const_cast</code>: |
---|
254 | <pre><code> |
---|
255 | ar & const_cast<T &>(t); |
---|
256 | </code></pre> |
---|
257 | Note that this violates the spirit and intention of the <code style="white-space: normal">const</code> |
---|
258 | keyword. <code style="white-space: normal">const</code> members are intialized when a class instance |
---|
259 | is constructed and not changed thereafter. However, this may |
---|
260 | be most appropriate in many cases. Ultimately, it comes down to |
---|
261 | the question about what <code style="white-space: normal">const</code> means in the context |
---|
262 | of serialization. |
---|
263 | |
---|
264 | <h4><a name="templates"></a>Templates</h4> |
---|
265 | Implementation serialization for templates is exactly the same process |
---|
266 | as for normal classes and requires no additional considerations. Among |
---|
267 | other things, this implies that serialization of compositions of templates |
---|
268 | are automatically generated when required if serialization of the |
---|
269 | component templates is defined. For example, this library includes |
---|
270 | definition of serialization for <code style="white-space: normal">boost::shared_ptr<T></code> and for |
---|
271 | <code style="white-space: normal">std::list<T></code>. If I have defined serialization for my own |
---|
272 | class <code style="white-space: normal">my_t</code>, then serialization for |
---|
273 | <code style="white-space: normal">std::list< boost::shared_ptr< my_t> ></code> is already available |
---|
274 | for use. |
---|
275 | <p> |
---|
276 | See for an example that shows how this idea might be implemented for your own |
---|
277 | class templates, see |
---|
278 | <a href="../example/demo_auto_ptr.cpp" target="demo_auto_ptr.cpp"> |
---|
279 | demo_auto_ptr.cpp</a>. |
---|
280 | This shows how non-intrusive serialization |
---|
281 | for the template <code style="white-space: normal">auto_ptr</code> from the standard library |
---|
282 | can be implemented. |
---|
283 | <p> |
---|
284 | A somewhat trickier addition of serialization to a standard template |
---|
285 | can be found in the example |
---|
286 | <a href="../../../boost/serialization/shared_ptr.hpp" target="shared_ptr_hpp"> |
---|
287 | shared_ptr.hpp |
---|
288 | </a> |
---|
289 | <!-- |
---|
290 | Only the most minimal change to |
---|
291 | <code>shared_count.hpp</code> |
---|
292 | (to gain access to some private members) was necessary to achieve this. |
---|
293 | This should demonstrate how easy it is to non-intrusively |
---|
294 | implement serialization to any data type or template. |
---|
295 | --> |
---|
296 | <p> |
---|
297 | In the specification of serialization for templates, its common |
---|
298 | to split <code style="white-space: normal">serialize</code> |
---|
299 | into a <code style="white-space: normal">load/save</code> pair. |
---|
300 | Note that the convenience macro described |
---|
301 | <a href="#BOOST_SERIALIZATION_SPLIT_FREE">above</a> |
---|
302 | isn't helpful in these cases as the number and kind of |
---|
303 | template class arguments won't match those used when splitting |
---|
304 | <code style="white-space: normal">serialize</code> for a simple class. Use the override |
---|
305 | syntax instead. |
---|
306 | |
---|
307 | <h3><a name="versioning">Versioning</a></h3> |
---|
308 | It will eventually occur that class definitions change after archives have |
---|
309 | been created. When a class instance is saved, the current version |
---|
310 | in included in the class information stored in the archive. When the class instance |
---|
311 | is loaded from the archive, the original version number is passed as an |
---|
312 | argument to the loading function. This permits the load function to include |
---|
313 | logic to accommodate older definitions for the class and reconcile them |
---|
314 | with latest version. Save functions always save the current version. So this |
---|
315 | results in automatically converting older format archives to the newest versions. |
---|
316 | Version numbers are maintained independently for each class. This results in |
---|
317 | a simple system for permitting access to older files and conversion of same. |
---|
318 | The current version of the class is assigned as a |
---|
319 | <a href="traits.html">Class Serialization Trait</a> described later in this manual. |
---|
320 | <pre><code> |
---|
321 | { |
---|
322 | // invoke serialization of the base class |
---|
323 | ar & boost::serialization::base_object<base_class_of_T>(*this); |
---|
324 | // save/load class member variables |
---|
325 | ar & member1; |
---|
326 | ar & member2; |
---|
327 | // if its a recent version of the class |
---|
328 | if(1 < file_version) |
---|
329 | // save load recently added class members |
---|
330 | ar & member3; |
---|
331 | } |
---|
332 | </code></pre> |
---|
333 | |
---|
334 | <h3><a name="splitting">Splitting <code style="white-space: normal">serialize</code> into Save/Load</a></h3> |
---|
335 | There are times when it is inconvenient to use the same |
---|
336 | template for both save and load functions. For example, this might occur if versioning |
---|
337 | gets complex. |
---|
338 | |
---|
339 | <h4><a name="splittingmemberfunctions">Splitting Member Functions</a></h4> |
---|
340 | For member functions this can be addressed by including |
---|
341 | the header file <a href="../../../boost/serialization/split_member.hpp" target="split_member_hpp"> |
---|
342 | boost/serialization/split_member.hpp</a> including code like this in the class: |
---|
343 | <pre><code> |
---|
344 | template<class Archive> |
---|
345 | void save(Archive & ar, const unsigned int version) const |
---|
346 | { |
---|
347 | // invoke serialization of the base class |
---|
348 | ar << boost::serialization::base_object<const base_class_of_T>(*this); |
---|
349 | ar << member1; |
---|
350 | ar << member2; |
---|
351 | ar << member3; |
---|
352 | } |
---|
353 | |
---|
354 | template<class Archive> |
---|
355 | void load(Archive & ar, const unsigned int version) |
---|
356 | { |
---|
357 | // invoke serialization of the base class |
---|
358 | ar >> boost::serialization::base_object<base_class_of_T>(*this); |
---|
359 | ar >> member1; |
---|
360 | ar >> member2; |
---|
361 | if(version > 0) |
---|
362 | ar >> member3; |
---|
363 | } |
---|
364 | |
---|
365 | template<class Archive> |
---|
366 | void serialize( |
---|
367 | Archive & ar, |
---|
368 | const unsigned int file_version |
---|
369 | ){ |
---|
370 | boost::serialization::split_member(ar, *this, file_version); |
---|
371 | } |
---|
372 | </code></pre> |
---|
373 | This splits the serialization into two separate functions <code style="white-space: normal">save</code> |
---|
374 | and <code style="white-space: normal">load</code>. Since the new <code style="white-space: normal">serialize</code> template |
---|
375 | is always the same it can be generated by invoking the macro |
---|
376 | BOOST_SERIALIZATION_SPLIT_MEMBER() defined in the header file |
---|
377 | <a href="../../../boost/serialization/split_member.hpp" target="split_member_hpp"> |
---|
378 | boost/serialization/split_member.hpp |
---|
379 | </a>. |
---|
380 | So the entire <code style="white-space: normal">serialize</code> function above can be replaced with: |
---|
381 | <pre><code> |
---|
382 | BOOST_SERIALIZATION_SPLIT_MEMBER() |
---|
383 | </code></pre> |
---|
384 | <h4><a name="splittingfreefunctions">Splitting Free Functions</a></h4> |
---|
385 | The situation is same for non-intrusive serialization with the free |
---|
386 | <code style="white-space: normal">serialize</code> function template. |
---|
387 | |
---|
388 | <a name="BOOST_SERIALIZATION_SPLIT_FREE"> |
---|
389 | To use <code style="white-space: normal">save</code> and |
---|
390 | <code style="white-space: normal">load</code> function templates rather than |
---|
391 | <code style="white-space: normal">serialize</code>: |
---|
392 | <pre><code> |
---|
393 | namespace boost { namespace serialization { |
---|
394 | template<class Archive> |
---|
395 | void save(Archive & ar, const my_class & t, unsigned int version) |
---|
396 | { |
---|
397 | ... |
---|
398 | } |
---|
399 | template<class Archive> |
---|
400 | void load(Archive & ar, my_class & t, unsigned int version) |
---|
401 | { |
---|
402 | ... |
---|
403 | } |
---|
404 | }} |
---|
405 | </code></pre> |
---|
406 | include the header file |
---|
407 | <a href="../../../boost/serialization/split_free.hpp" target="split_free_hpp"> |
---|
408 | boost/serialization/split_free.hpp |
---|
409 | </a>. |
---|
410 | and override the free <code style="white-space: normal">serialize</code> function template: |
---|
411 | <pre><code> |
---|
412 | namespace boost { namespace serialization { |
---|
413 | template<class Archive> |
---|
414 | inline void serialize( |
---|
415 | Archive & ar, |
---|
416 | my_class & t, |
---|
417 | const unsigned int file_version |
---|
418 | ){ |
---|
419 | split_free(ar, t, file_version); |
---|
420 | } |
---|
421 | }} |
---|
422 | </code></pre> |
---|
423 | To shorten typing, the above template can be replaced with |
---|
424 | the macro: |
---|
425 | <pre><code> |
---|
426 | BOOST_SERIALIZATION_SPLIT_FREE(my_class) |
---|
427 | </code></pre> |
---|
428 | |
---|
429 | Note that although the functionality to split the <code style="white-space: normal"> |
---|
430 | serialize</code> function into <code style="white-space: normal">save/load</code> |
---|
431 | has been provided, the usage of the <code style="white-space: normal">serialize</code> |
---|
432 | function with the corresponding <code style="white-space: normal">&</code> operator |
---|
433 | is preferred. The key to the serialization implementation is that objects are saved |
---|
434 | and loaded in exactly the same sequence. Using the <code style="white-space: normal">&</code> |
---|
435 | operator and <code style="white-space: normal">serialize</code> |
---|
436 | function guarantees that this is always the case and will minimize the |
---|
437 | occurence of hard to find errors related to synchronization of |
---|
438 | <code style="white-space: normal">save</code> and <code style="white-space: normal">load</code> |
---|
439 | functions. |
---|
440 | |
---|
441 | <h2><a name="pointeroperators">Pointers</a></h2> |
---|
442 | A pointer to any class instance can be serialized with any of the archive |
---|
443 | save/load operators. |
---|
444 | <p> |
---|
445 | To properly save and restore an object through a pointer the |
---|
446 | following situations must be addressed: |
---|
447 | <ol> |
---|
448 | <li>If the same object is saved multiple times through different |
---|
449 | pointers, only one copy of the object need be saved. |
---|
450 | <li>If an object is loaded multiple times through different pointers, |
---|
451 | only one new object should be created and all returned pointers |
---|
452 | should point to it. |
---|
453 | <li>The system must detect the case where an object is first |
---|
454 | saved through a pointer then the object itself is saved. |
---|
455 | Without taking extra precautions, loading would result in the |
---|
456 | creation of multiple copies of the original object. This system detects |
---|
457 | this case when saving and throws an exception - see below. |
---|
458 | <li>An object of a derived class may be stored through a |
---|
459 | pointer to the base class. The true type of the object must |
---|
460 | be determined and saved. Upon restoration the correct type |
---|
461 | must be created and its address correctly cast to the base |
---|
462 | class. That is, polymorphic pointers have to be considered. |
---|
463 | <li>NULL pointers must be dectected when saved and restored |
---|
464 | to NULL when deserialized. |
---|
465 | </ol> |
---|
466 | |
---|
467 | This serialization library addresses all of the above |
---|
468 | considerations. The process of saving and loading an object |
---|
469 | through a pointer is non-trivial. It can be summarized as |
---|
470 | follows: |
---|
471 | <p>Saving a pointer: |
---|
472 | <ol> |
---|
473 | <li>determine the true type of the object being pointed to. |
---|
474 | <li>write a special tag to the archive |
---|
475 | <li>if the object pointed to has not already been written |
---|
476 | to the archive, do so now |
---|
477 | </ol> |
---|
478 | Loading a pointer: |
---|
479 | <ol> |
---|
480 | <li>read a tag from the archive. |
---|
481 | <li>determine the type of object to be created |
---|
482 | <li>if the object has already been loaded, return it's address. |
---|
483 | <li>otherwise, create a new instance of the object |
---|
484 | <li>read the data back in using the operators described above |
---|
485 | <li>return the address of the newly created object. |
---|
486 | </ol> |
---|
487 | |
---|
488 | Given that class instances are saved/loaded to/from the archive |
---|
489 | only once, regardless of how many times they are serialized with |
---|
490 | the <code style="white-space: normal"><<</code> |
---|
491 | and <code style="white-space: normal">>></code> operators |
---|
492 | <ul> |
---|
493 | <li>Loading the same pointer object multiple times |
---|
494 | results in only one object being created, thereby replicating |
---|
495 | the original pointer configuration. |
---|
496 | <li>Structures such as collections of polymorphic pointers, |
---|
497 | are handled with no special effort on the part of users of this library. |
---|
498 | </ul> |
---|
499 | Serialization of pointers of derived types through a pointer to the |
---|
500 | base class may require a little extra "help". Also, the programmer |
---|
501 | may desire to modify the process described above for his own reasons. |
---|
502 | For example, it might be desired to suppress the tracking of objects |
---|
503 | as it is known a priori that the application in question can never |
---|
504 | create duplicate objects. Serialization of pointers can be "fine tuned" |
---|
505 | via the specification of <a target="detail" href="traits.html#Traits">Class Serialization Traits</a> |
---|
506 | as described in |
---|
507 | <a target="detail" href="special.html#derivedpointers"> |
---|
508 | another section of this manual |
---|
509 | </a> |
---|
510 | |
---|
511 | <h3><a name="constructors">Non-Default Constructors</a></h3> |
---|
512 | Serialization of pointers is implemented in the library with code |
---|
513 | similar to the following: |
---|
514 | <pre><code> |
---|
515 | // load data required for construction and invoke constructor in place |
---|
516 | template<class Archive, class T> |
---|
517 | inline void load_construct_data( |
---|
518 | Archive & ar, T * t, const unsigned int file_version |
---|
519 | ){ |
---|
520 | // default just uses the default constructor to initialize |
---|
521 | // previously allocated memory. |
---|
522 | ::new(t)T(); |
---|
523 | } |
---|
524 | </code></pre> |
---|
525 | The default <code style="white-space: normal">load_construct_data</code> invokes the |
---|
526 | default constructor "in-place" to initialize the memory. |
---|
527 | <p> |
---|
528 | If there is no such default constructor, the function templates |
---|
529 | <code style="white-space: normal">load_construct_data</code> and |
---|
530 | perhaps <code style="white-space: normal">save_construct_data</code> |
---|
531 | will have to be overridden. Here is a simple example: |
---|
532 | <pre><code> |
---|
533 | class my_class { |
---|
534 | private: |
---|
535 | friend class boost::serialization::access; |
---|
536 | int member; |
---|
537 | template<class Archive> |
---|
538 | void serialize(Archive &ar, const unsigned int file_version){ |
---|
539 | ar & member; |
---|
540 | } |
---|
541 | public: |
---|
542 | my_class(int m) : |
---|
543 | member(m) |
---|
544 | {} |
---|
545 | }; |
---|
546 | </code></pre> |
---|
547 | the overrides would be: |
---|
548 | <pre><code> |
---|
549 | namespace boost { namespace serialization { |
---|
550 | template<class Archive> |
---|
551 | inline void save_construct_data( |
---|
552 | Archive & ar, const my_class * t, const unsigned int file_version |
---|
553 | ){ |
---|
554 | // save data required to construct instance |
---|
555 | ar << t->member; |
---|
556 | } |
---|
557 | |
---|
558 | template<class Archive> |
---|
559 | inline void load_construct_data( |
---|
560 | Archive & ar, my_class * t, const unsigned int file_version |
---|
561 | ){ |
---|
562 | // retrieve data from archive required to construct new instance |
---|
563 | int m; |
---|
564 | ar >> m; |
---|
565 | // invoke inplace constructor to initialize instance of my_class |
---|
566 | ::new(t)my_class(m); |
---|
567 | } |
---|
568 | }} // namespace ... |
---|
569 | </code></pre> |
---|
570 | In addition to the deserialization of pointers, these overrides are used |
---|
571 | in the deserialization of STL containers whose element type has no default |
---|
572 | constructor. |
---|
573 | |
---|
574 | <h3><a name="derivedpointers">Pointers to Objects of Derived Classes</a></h3> |
---|
575 | <h4><a name="registration">Registration</a></h4> |
---|
576 | Consider the following: |
---|
577 | <pre><code> |
---|
578 | class base { |
---|
579 | ... |
---|
580 | }; |
---|
581 | class derived_one : public base { |
---|
582 | ... |
---|
583 | }; |
---|
584 | class derived_two : public base { |
---|
585 | ... |
---|
586 | }; |
---|
587 | main(){ |
---|
588 | ... |
---|
589 | base *b; |
---|
590 | ... |
---|
591 | ar & b; |
---|
592 | } |
---|
593 | </code></pre> |
---|
594 | When saving <code style="white-space: normal">b</code> what kind of object should be saved? |
---|
595 | When loading <code style="white-space: normal">b</code> what kind of object should be created? |
---|
596 | Should it be an object of class <code style="white-space: normal">derived_one</code>, |
---|
597 | <code style="white-space: normal">derived_two</code>, or maybe <code style="white-space: normal">base</code>? |
---|
598 | <p> |
---|
599 | It turns out that the kind of object serialized depends upon whether the base class |
---|
600 | (<code style="white-space: normal">base</code> in this case) is polymophic or not. |
---|
601 | If <code style="white-space: normal">base</code> is not polymorphic, that is if it has no |
---|
602 | virtual functions, then an object of the type <code style="white-space: normal">base</code> |
---|
603 | will be serialized. Information in any derived classes will be lost. If this is what is desired |
---|
604 | (it usually isn't) then no other effort is required. |
---|
605 | <p> |
---|
606 | |
---|
607 | If the base class is polymorphic, an object of the most derived type |
---|
608 | (<code style="white-space: normal">derived_one</code> |
---|
609 | or <code style="white-space: normal">derived_two</code> |
---|
610 | in this case) will be serialized. The question of which type of object is to be |
---|
611 | serialized is (almost) automatically handled by the library. |
---|
612 | <p> |
---|
613 | The system "registers" each class in an archive the first time an object of that |
---|
614 | class it is serialized and assigns a sequential number to it. Next time an |
---|
615 | object of that class is serialized in that same archive, this number is written |
---|
616 | in the archive. So every class is identified uniquely within the archive. |
---|
617 | When the archive is read back in, each new sequence number is re-associated with |
---|
618 | the class being read. Note that this implies that "registration" has to occur |
---|
619 | during both save and load so that the class-integer table built on load |
---|
620 | is identical to the class-integer table built on save. In fact, the key to |
---|
621 | whole serialization system is that things are always saved and loaded in |
---|
622 | the same sequence. This includes "registration". |
---|
623 | <p> |
---|
624 | Expanding our previous example: |
---|
625 | <pre><code> |
---|
626 | main(){ |
---|
627 | derived_one d1; |
---|
628 | derived_two d2: |
---|
629 | ... |
---|
630 | ar & d1; |
---|
631 | ar & d2; |
---|
632 | // A side effect of serialization of objects d1 and d2 is that |
---|
633 | // the classes derived_one and derived_two become known to the archive. |
---|
634 | // So subsequent serialization of those classes by base pointer works |
---|
635 | // without any special considerations. |
---|
636 | base *b; |
---|
637 | ... |
---|
638 | ar & b; |
---|
639 | } |
---|
640 | </code></pre> |
---|
641 | When <code style="white-space: normal">b</code> is read it is |
---|
642 | preceded by a unique (to the archive) class identifier which |
---|
643 | has previously been related to class <code style="white-space: normal">derived_one</code> or |
---|
644 | <code style="white-space: normal">derived_two</code>. |
---|
645 | <p> |
---|
646 | If a derived class has NOT been automatically "registered" as described |
---|
647 | above, an <a target="detail" href="exceptions.html#unregistered_class"> |
---|
648 | <code style="white-space: normal">unregistered_class</code></a> exception |
---|
649 | will be thrown when serialization is invoked. |
---|
650 | <p> |
---|
651 | This can be addressed by registering the derived class explicitly. All archives are |
---|
652 | derived from a base class which implements the following template: |
---|
653 | <pre><code> |
---|
654 | template<class T> |
---|
655 | register_type(); |
---|
656 | </code></pre> |
---|
657 | So our problem could just as well be addressed by writing: |
---|
658 | <pre><code> |
---|
659 | main(){ |
---|
660 | ... |
---|
661 | ar.template register_type<derived_one>(); |
---|
662 | ar.template register_type<derived_two>(); |
---|
663 | base *b; |
---|
664 | ... |
---|
665 | ar & b; |
---|
666 | } |
---|
667 | </code></pre> |
---|
668 | Note that if the serialization function is split between save and load, both |
---|
669 | functions must include the registration. This is required to keep the save |
---|
670 | and corresponding load in syncronization. |
---|
671 | <p> |
---|
672 | This will work but may be inconvenient. We don't always know which derived |
---|
673 | classes we are going to serialize when we write the code to serialize through |
---|
674 | a base class pointer. Every time a new derived class is written we have to |
---|
675 | go back to all the places where the base class is serialized and update the |
---|
676 | code. |
---|
677 | <p> |
---|
678 | So we have another method: |
---|
679 | <pre><code> |
---|
680 | #include <boost/serialization/export.hpp> |
---|
681 | ... |
---|
682 | BOOST_CLASS_EXPORT_GUID(derived_one, "derived_one") |
---|
683 | BOOST_CLASS_EXPORT_GUID(derived_two, "derived_two") |
---|
684 | |
---|
685 | main(){ |
---|
686 | ... |
---|
687 | base *b; |
---|
688 | ... |
---|
689 | ar & b; |
---|
690 | } |
---|
691 | </code></pre> |
---|
692 | The macro <code style="white-space: normal">BOOST_CLASS_EXPORT_GUID</code> associates a string literal |
---|
693 | with a class. In the above example we've used a string rendering |
---|
694 | of the class name. If a object of such an "exported" class is serialized |
---|
695 | through a pointer and is otherwise unregistered, the "export" string is |
---|
696 | included in the archive. When the archive |
---|
697 | is later read, the string literal is used to find the class which |
---|
698 | should be created by the serialization library. |
---|
699 | This permits each class to be in a separate header file along with its |
---|
700 | string identifier. There is no need to maintain a separate "pre-registration" |
---|
701 | of derived classes that might be serialized. This method of |
---|
702 | registration is referred to as "key export". More information on this |
---|
703 | topic is found in the section Class Traits - |
---|
704 | <a target="detail" href="traits.html#export">Export Key</a>. |
---|
705 | <p> |
---|
706 | <h4><a name="instantiation">Instantiation</a></h4> |
---|
707 | Registration by means of any of the above methods fulfill another role |
---|
708 | whose importance might not be obvious. This system relies on templated |
---|
709 | functions of the form <code style="white-space: normal">template<class Archive, class T></code>. |
---|
710 | This means that serialization code must be instantiated for each |
---|
711 | combination of archive and data type that is serialized in the program. |
---|
712 | <p> |
---|
713 | Polymorphic pointers of derived classes may never be referred to |
---|
714 | explictly by the program so normally code to serialize such classes |
---|
715 | would never be instantiated. So in addition to including export key |
---|
716 | strings in an archive, <code style="white-space: normal">BOOST_CLASS_EXPORT_GUID</code> explicitly |
---|
717 | instantiates the class serialization code for all archive classes used |
---|
718 | by the program. |
---|
719 | <p> |
---|
720 | In order to do this, |
---|
721 | <a href="../../../boost/serialization/export.hpp" target="export_hpp">export.hpp</a> |
---|
722 | includes meta programming code to build a <code style="white-space: normal">mpl::list</code> |
---|
723 | of all the file types used by the module by checking for definition of the header |
---|
724 | inclusion guards. |
---|
725 | |
---|
726 | Using this list, |
---|
727 | <code style="white-space: normal">BOOST_CLASS_EXPORT_GUID</code> will explicitly instantiate serialization |
---|
728 | code for all exported classes. |
---|
729 | For this implementaton to function, the header file |
---|
730 | <a href="../../../boost/serialization/export.hpp" target="export_hpp">export.hpp</a> |
---|
731 | has to come after all the archive header files. This is enforced |
---|
732 | by code at the end of the header file: |
---|
733 | <a href="../../../boost/archive/basic_archive.hpp" target="basic_archive_hpp">basic_archive.hpp</a> |
---|
734 | which will trip a STATIC_ASSERT if this requirement is violated. |
---|
735 | |
---|
736 | <h4><a name="selectivetracking">Selective Tracking</a></h4> |
---|
737 | Whether or not an object is tracked is determined by its |
---|
738 | <a target="detail" href="traits.html#tracking">object tracking trait</a>. |
---|
739 | The default setting for user defined types is <code style="white-space: normal">track_selectively</code>. |
---|
740 | That is, track objects if and only if they are serialized through pointers anywhere |
---|
741 | in the program. Any objects that are "registered" by any of the above means are presumed |
---|
742 | to be serialized through pointers somewhere in the program and therefore |
---|
743 | would be tracked. In certain situations this could lead to an inefficiency. |
---|
744 | Suppose we have a class module used by multiple programs. Because |
---|
745 | some programs serializes polymorphic pointers to objects of this class, we |
---|
746 | <a target="detail" href="traits.html#export">export</a> a class |
---|
747 | identifier by specifying <code style="white-space: normal">BOOST_CLASS_EXPORT</code> in the |
---|
748 | class header. When this module is included by another program, |
---|
749 | objects of this class will always be tracked even though it |
---|
750 | may not be necessary. This situation could be addressed by using |
---|
751 | <a target="detail" href="traits.html#tracking"><code style="white-space: normal">track_never</code></a> |
---|
752 | in those programs. |
---|
753 | <p> |
---|
754 | It could also occur that even though a program serializes through |
---|
755 | a pointer, we are more concerned with efficiency than avoiding the |
---|
756 | the possibility of creating duplicate objects. It could be |
---|
757 | that we happen to know that there will be no duplicates. It could |
---|
758 | also be that the creation of a few duplicates is benign and not |
---|
759 | worth avoiding given the runtime cost of tracking duplicates. |
---|
760 | Again, <a target="detail" href="traits.html#tracking"><code style="white-space: normal">track_never</code></a> |
---|
761 | can be used. |
---|
762 | <h4><a name="runtimecasting">Runtime Casting</a></h4> |
---|
763 | In order to properly translate between base and derived pointers |
---|
764 | at runtime, the system requires each base/derived pair be found |
---|
765 | in a table. A side effect of serializing a base object with |
---|
766 | <code style="white-space: normal">boost::serialization::base_object<Base>(Derived &)</code> |
---|
767 | is to ensure that the base/derived pair is added to the table |
---|
768 | before the <code style="white-space: normal">main</code> function is entered. |
---|
769 | This is very convenient and results in a clean syntax. The only |
---|
770 | problem is that it can occur where a derived class serialized |
---|
771 | through a pointer has no need to invoke the serialization of |
---|
772 | its base class. In such a case, there are two choices. The obvious |
---|
773 | one is to invoke the base class serialization with <code style="white-space: normal">base_object</code> |
---|
774 | and specify an empty function for the base class serialization. |
---|
775 | The alternative is to "register" the Base/Derived relationship |
---|
776 | explicitly by invoking the template |
---|
777 | <code style="white-space: normal">void_cast_register<Derived, Base>();</code>. |
---|
778 | Note that this usage of the term "register" is not related |
---|
779 | to its usage in the previous section. Here is an example of how this is done: |
---|
780 | <pre><code> |
---|
781 | #include <sstream> |
---|
782 | #include <boost/serialization/serialization.hpp> |
---|
783 | #include <boost/archive/text_iarchive.hpp> |
---|
784 | #include <boost/serialization/export.hpp> |
---|
785 | |
---|
786 | class base { |
---|
787 | friend class boost::serialization::access; |
---|
788 | //... |
---|
789 | // only required when using method 1 below |
---|
790 | // no real serialization required - specify a vestigial one |
---|
791 | template<class Archive> |
---|
792 | void serialize(Archive & ar, const unsigned int file_version){} |
---|
793 | }; |
---|
794 | |
---|
795 | class derived : public base { |
---|
796 | friend class boost::serialization::access; |
---|
797 | template<class Archive> |
---|
798 | void serialize(Archive & ar, const unsigned int file_version){ |
---|
799 | // method 1 : invoke base class serialization |
---|
800 | boost::serialization::base_object<base>(*this); |
---|
801 | // method 2 : explicitly register base/derived relationship |
---|
802 | boost::serialization::void_cast_register<derived, base>(); |
---|
803 | } |
---|
804 | }; |
---|
805 | |
---|
806 | BOOST_CLASS_EXPORT_GUID(derived, "derived") |
---|
807 | |
---|
808 | main(){ |
---|
809 | //... |
---|
810 | std::stringstream ss; |
---|
811 | boost::archive::text_iarchive ar(ss); |
---|
812 | base *b; |
---|
813 | ar >> b; |
---|
814 | } |
---|
815 | </code></pre> |
---|
816 | <p> |
---|
817 | |
---|
818 | In order for this template to be invoked in code compiled by non-conforming |
---|
819 | compilers, the following syntax may be used: |
---|
820 | <pre><code> |
---|
821 | boost::serialization::void_cast_register( |
---|
822 | static_cast<Derived *>(NULL), |
---|
823 | static_cast<Base *>(NULL) |
---|
824 | ); |
---|
825 | </code></pre> |
---|
826 | For more information, see <a target="detail" href="implementation.html#tempatesyntax">Template Invocation syntax</a> |
---|
827 | |
---|
828 | <h3><a name="references"></a>References</h3> |
---|
829 | Classes that contain reference members will generally require |
---|
830 | non-default constructors as references can only be set when |
---|
831 | an instance is constructed. The example of the previous section |
---|
832 | is slightly more complex if the class has reference members. |
---|
833 | This raises the question of how and where the objects being |
---|
834 | referred to are stored and how are they created. Also there is the question about |
---|
835 | references to polymorphic base classes. Basically, these |
---|
836 | are the same questions that arise regarding pointers. This is |
---|
837 | no surprise as references are really a special kind of pointer. |
---|
838 | We address these questions by serializing references as though |
---|
839 | they were pointers. |
---|
840 | <pre><code> |
---|
841 | class object; |
---|
842 | class my_class { |
---|
843 | private: |
---|
844 | friend class boost::serialization::access; |
---|
845 | int member1; |
---|
846 | object & member2; |
---|
847 | template<class Archive> |
---|
848 | void serialize(Archive &ar, const unsigned int file_version); |
---|
849 | public: |
---|
850 | my_class(int m, object & o) : |
---|
851 | member1(m), |
---|
852 | member2(o) |
---|
853 | {} |
---|
854 | }; |
---|
855 | </code></pre> |
---|
856 | the overrides would be: |
---|
857 | <pre><code> |
---|
858 | namespace boost { namespace serialization { |
---|
859 | template<class Archive> |
---|
860 | inline void save_construct_data( |
---|
861 | Archive & ar, const my_class * t, const unsigned int file_version |
---|
862 | ){ |
---|
863 | // save data required to construct instance |
---|
864 | ar << t.member1; |
---|
865 | // serialize reference to object as a pointer |
---|
866 | ar << & t.member2; |
---|
867 | } |
---|
868 | |
---|
869 | template<class Archive> |
---|
870 | inline void load_construct_data( |
---|
871 | Archive & ar, my_class * t, const unsigned int file_version |
---|
872 | ){ |
---|
873 | // retrieve data from archive required to construct new instance |
---|
874 | int m; |
---|
875 | ar >> m; |
---|
876 | // create and load data through pointer to object |
---|
877 | // tracking handles issues of duplicates. |
---|
878 | object * optr; |
---|
879 | ar >> optr; |
---|
880 | // invoke inplace constructor to initialize instance of my_class |
---|
881 | ::new(t)my_class(m, *optr); |
---|
882 | } |
---|
883 | }} // namespace ... |
---|
884 | </code></pre> |
---|
885 | |
---|
886 | <h3><a name="arrays"></a>Arrays</h3> |
---|
887 | If <code style="white-space: normal">T</code> is a serializable type, |
---|
888 | then any native C++ array of type T is a serializable type. |
---|
889 | That is, if <code style="white-space: normal">T</code> |
---|
890 | is a serializable type, then the following |
---|
891 | is automatically available and will function as expected: |
---|
892 | <pre><code> |
---|
893 | T t[4]; |
---|
894 | ar << t; |
---|
895 | ... |
---|
896 | ar >> t; |
---|
897 | </code></pre> |
---|
898 | |
---|
899 | <h2><a href="traits.html">Class Serialization Traits</a></h2> |
---|
900 | |
---|
901 | <h2><a href="wrappers.html">Serialization Wrappers</a></h2> |
---|
902 | |
---|
903 | <h2><a name="models"></a>Models - Serialization Implementations Included in the Library</h2> |
---|
904 | The facilities described above are sufficient to implement |
---|
905 | serialization for all STL containers. In fact, this has been done |
---|
906 | and has been included in the library. For example, in order to use |
---|
907 | the included serialization code for <code style="white-space: normal">std::list</code>, use: |
---|
908 | <pre><code> |
---|
909 | #include <boost/serialization/list.hpp> |
---|
910 | </code></pre> |
---|
911 | rather than |
---|
912 | <pre><code> |
---|
913 | #include <list> |
---|
914 | </code></pre> |
---|
915 | Since the former includes the latter, this all that is necessary. |
---|
916 | The same holds true for all STL collections as well as templates |
---|
917 | required to support them (e.g. <code style="white-space: normal">std::pair</code>). |
---|
918 | <p> |
---|
919 | As of this writing, the library contains serialization of the following boost clases: |
---|
920 | <ul> |
---|
921 | <li>optional |
---|
922 | <li>variant |
---|
923 | <li>scoped_ptr |
---|
924 | <li>shared_ptr |
---|
925 | <li>auto_ptr (demo) |
---|
926 | </ul> |
---|
927 | Others are being added to the list so check the boost files section and headers for |
---|
928 | new implmentations! |
---|
929 | <hr> |
---|
930 | <p><i>© Copyright <a href="http://www.rrsd.com">Robert Ramey</a> 2002-2004. |
---|
931 | Distributed under the Boost Software License, Version 1.0. (See |
---|
932 | accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
---|
933 | </i></p> |
---|
934 | </body> |
---|
935 | </html> |
---|