]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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="#pointeroperators">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="#export">Export</a> | |
58 | <dt><a href="#instantiation">Instantiation</a> | |
59 | <dt><a href="#selectivetracking">Selective Tracking</a> | |
60 | <dt><a href="#runtimecasting">Runtime Casting</a> | |
61 | </dl> | |
62 | </dl> | |
63 | <dt><a href="#references">References</a> | |
64 | <dt><a href="#arrays">Arrays</a> | |
65 | <dt><a href="traits.html">Class Serialization Traits</a> | |
66 | <dt><a href="wrappers.html">Serialization Wrappers</a> | |
67 | <dt><a href="#models">Models - Serialization Implementations Included in the Library</a> | |
68 | </dl> | |
69 | ||
70 | A type <code style="white-space: normal">T</code> is <strong>Serializable</strong> | |
71 | if and only if one of the following is true: | |
72 | <ul> | |
73 | <li>it is a primitive type.<br> | |
74 | By <i>primitive type</i> we mean a C++ built-in type and <i>ONLY</i> | |
75 | a C++ built-in type. Arithmetic (including characters), bool, enum are primitive types. | |
76 | Below in <a target="detail" href="traits.html#Traits">serialization traits</a>, | |
77 | we define a "primitive" implementation level in a different way for a | |
78 | different purpose. This can be a source of confusion. | |
79 | <li>It is a class type and one of the following has been declared according | |
80 | to the prototypes detailed below: | |
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 a 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 the 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 further 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 of 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 | 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 | occurrence 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 | <p> | |
441 | Also note that <code style="white-space: normal">BOOST_SERIALIZATION_SPLIT_FREE</code> | |
442 | must be used outside of any namespace. | |
443 | ||
444 | <h2><a name="pointeroperators">Pointers</a></h2> | |
445 | A pointer to any class instance can be serialized with any of the archive | |
446 | save/load operators. | |
447 | <p> | |
448 | To properly save and restore an object through a pointer the | |
449 | following situations must be addressed: | |
450 | <ol> | |
451 | <li>If the same object is saved multiple times through different | |
452 | pointers, only one copy of the object need be saved. | |
453 | <li>If an object is loaded multiple times through different pointers, | |
454 | only one new object should be created and all returned pointers | |
455 | should point to it. | |
456 | <li>The system must detect the case where an object is first | |
457 | saved through a pointer then the object itself is saved. | |
458 | Without taking extra precautions, loading would result in the | |
459 | creation of multiple copies of the original object. This system detects | |
460 | this case when saving and throws an exception - see below. | |
461 | <li>An object of a derived class may be stored through a | |
462 | pointer to the base class. The true type of the object must | |
463 | be determined and saved. Upon restoration the correct type | |
464 | must be created and its address correctly cast to the base | |
465 | class. That is, polymorphic pointers have to be considered. | |
466 | <li>NULL pointers must be dectected when saved and restored | |
467 | to NULL when deserialized. | |
468 | </ol> | |
469 | ||
470 | This serialization library addresses all of the above | |
471 | considerations. The process of saving and loading an object | |
472 | through a pointer is non-trivial. It can be summarized as | |
473 | follows: | |
474 | <p>Saving a pointer: | |
475 | <ol> | |
476 | <li>determine the true type of the object being pointed to. | |
477 | <li>write a special tag to the archive | |
478 | <li>if the object pointed to has not already been written | |
479 | to the archive, do so now | |
480 | </ol> | |
481 | Loading a pointer: | |
482 | <ol> | |
483 | <li>read a tag from the archive. | |
484 | <li>determine the type of object to be created | |
485 | <li>if the object has already been loaded, return its address. | |
486 | <li>otherwise, create a new instance of the object | |
487 | <li>read the data back in using the operators described above | |
488 | <li>return the address of the newly created object. | |
489 | </ol> | |
490 | ||
491 | Given that class instances are saved/loaded to/from the archive | |
492 | only once, regardless of how many times they are serialized with | |
493 | the <code style="white-space: normal"><<</code> | |
494 | and <code style="white-space: normal">>></code> operators | |
495 | <ul> | |
496 | <li>Loading the same pointer object multiple times | |
497 | results in only one object being created, thereby replicating | |
498 | the original pointer configuration. | |
499 | <li>Structures, such as collections of polymorphic pointers, | |
500 | are handled with no special effort on the part of users of this library. | |
501 | </ul> | |
502 | Serialization of pointers of derived types through a pointer to the | |
503 | base class may require a little extra "help". Also, the programmer | |
504 | may desire to modify the process described above for his own reasons. | |
505 | For example, it might be desired to suppress the tracking of objects | |
506 | as it is known a priori that the application in question can never | |
507 | create duplicate objects. Serialization of pointers can be "fine tuned" | |
508 | via the specification of <a target="detail" href="traits.html#Traits">Class Serialization Traits</a> | |
509 | as described in | |
510 | <a target="detail" href="special.html#derivedpointers"> | |
511 | another section of this manual | |
512 | </a> | |
513 | ||
514 | <h3><a name="constructors">Non-Default Constructors</a></h3> | |
515 | Serialization of pointers is implemented in the library with code | |
516 | similar to the following: | |
517 | <pre><code> | |
518 | // load data required for construction and invoke constructor in place | |
519 | template<class Archive, class T> | |
520 | inline void load_construct_data( | |
521 | Archive & ar, T * t, const unsigned int file_version | |
522 | ){ | |
523 | // default just uses the default constructor to initialize | |
524 | // previously allocated memory. | |
525 | ::new(t)T(); | |
526 | } | |
527 | </code></pre> | |
528 | The default <code style="white-space: normal">load_construct_data</code> invokes the | |
529 | default constructor "in-place" to initialize the memory. | |
530 | <p> | |
531 | If there is no such default constructor, the function templates | |
532 | <code style="white-space: normal">load_construct_data</code> and | |
533 | perhaps <code style="white-space: normal">save_construct_data</code> | |
534 | will have to be overridden. Here is a simple example: | |
535 | <pre><code> | |
536 | class my_class { | |
537 | private: | |
538 | friend class boost::serialization::access; | |
539 | const int m_attribute; // some immutable aspect of the instance | |
540 | int m_state; // mutable state of this instance | |
541 | template<class Archive> | |
542 | void serialize(Archive &ar, const unsigned int file_version){ | |
543 | ar & m_state; | |
544 | } | |
545 | public: | |
546 | // no default construct guarentees that no invalid object | |
547 | // ever exists | |
548 | my_class(int attribute) : | |
549 | m_attribute(attribute), | |
550 | m_state(0) | |
551 | {} | |
552 | }; | |
553 | </code></pre> | |
554 | the overrides would be: | |
555 | <pre><code> | |
556 | namespace boost { namespace serialization { | |
557 | template<class Archive> | |
558 | inline void save_construct_data( | |
559 | Archive & ar, const my_class * t, const unsigned int file_version | |
560 | ){ | |
561 | // save data required to construct instance | |
562 | ar << t->m_attribute; | |
563 | } | |
564 | ||
565 | template<class Archive> | |
566 | inline void load_construct_data( | |
567 | Archive & ar, my_class * t, const unsigned int file_version | |
568 | ){ | |
569 | // retrieve data from archive required to construct new instance | |
570 | int attribute; | |
571 | ar >> attribute; | |
572 | // invoke inplace constructor to initialize instance of my_class | |
573 | ::new(t)my_class(attribute); | |
574 | } | |
575 | }} // namespace ... | |
576 | </code></pre> | |
577 | In addition to the deserialization of pointers, these overrides are used | |
578 | in the deserialization of STL containers whose element type has no default | |
579 | constructor. | |
580 | ||
581 | <h3><a name="derivedpointers">Pointers to Objects of Derived Classes</a></h3> | |
582 | <h4><a name="registration">Registration</a></h4> | |
583 | Consider the following: | |
584 | <pre><code> | |
585 | class base { | |
586 | ... | |
587 | }; | |
588 | class derived_one : public base { | |
589 | ... | |
590 | }; | |
591 | class derived_two : public base { | |
592 | ... | |
593 | }; | |
594 | main(){ | |
595 | ... | |
596 | base *b; | |
597 | ... | |
598 | ar & b; | |
599 | } | |
600 | </code></pre> | |
601 | When saving <code style="white-space: normal">b</code> what kind of object should be saved? | |
602 | When loading <code style="white-space: normal">b</code> what kind of object should be created? | |
603 | Should it be an object of class <code style="white-space: normal">derived_one</code>, | |
604 | <code style="white-space: normal">derived_two</code>, or maybe <code style="white-space: normal">base</code>? | |
605 | <p> | |
606 | It turns out that the kind of object serialized depends upon whether the base class | |
607 | (<code style="white-space: normal">base</code> in this case) is polymophic or not. | |
608 | If <code style="white-space: normal">base</code> is not polymorphic, that is if it has no | |
609 | virtual functions, then an object of the type <code style="white-space: normal">base</code> | |
610 | will be serialized. Information in any derived classes will be lost. If this is what is desired | |
611 | (it usually isn't) then no other effort is required. | |
612 | <p> | |
613 | ||
614 | If the base class is polymorphic, an object of the most derived type | |
615 | (<code style="white-space: normal">derived_one</code> | |
616 | or <code style="white-space: normal">derived_two</code> | |
617 | in this case) will be serialized. The question of which type of object is to be | |
618 | serialized is (almost) automatically handled by the library. | |
619 | <p> | |
620 | The system "registers" each class in an archive the first time an object of that | |
621 | class it is serialized and assigns a sequential number to it. Next time an | |
622 | object of that class is serialized in that same archive, this number is written | |
623 | in the archive. So every class is identified uniquely within the archive. | |
624 | When the archive is read back in, each new sequence number is re-associated with | |
625 | the class being read. Note that this implies that "registration" has to occur | |
626 | during both save and load so that the class-integer table built on load | |
627 | is identical to the class-integer table built on save. In fact, the key to | |
628 | whole serialization system is that things are always saved and loaded in | |
629 | the same sequence. This includes "registration". | |
630 | <p> | |
631 | Expanding our previous example: | |
632 | <pre><code> | |
633 | main(){ | |
634 | derived_one d1; | |
635 | derived_two d2: | |
636 | ... | |
637 | ar & d1; | |
638 | ar & d2; | |
639 | // A side effect of serialization of objects d1 and d2 is that | |
640 | // the classes derived_one and derived_two become known to the archive. | |
641 | // So subsequent serialization of those classes by base pointer works | |
642 | // without any special considerations. | |
643 | base *b; | |
644 | ... | |
645 | ar & b; | |
646 | } | |
647 | </code></pre> | |
648 | When <code style="white-space: normal">b</code> is read it is | |
649 | preceded by a unique (to the archive) class identifier which | |
650 | has previously been related to class <code style="white-space: normal">derived_one</code> or | |
651 | <code style="white-space: normal">derived_two</code>. | |
652 | <p> | |
653 | If a derived class has NOT been automatically "registered" as described | |
654 | above, an <a target="detail" href="exceptions.html#unregistered_class"> | |
655 | <code style="white-space: normal">unregistered_class</code></a> exception | |
656 | will be thrown when serialization is invoked. | |
657 | <p> | |
658 | This can be addressed by registering the derived class explicitly. All archives are | |
659 | derived from a base class which implements the following template: | |
660 | <pre><code> | |
661 | template<class T> | |
662 | register_type(); | |
663 | </code></pre> | |
664 | So our problem could just as well be addressed by writing: | |
665 | <pre><code> | |
666 | main(){ | |
667 | ... | |
668 | ar.template register_type<derived_one>(); | |
669 | ar.template register_type<derived_two>(); | |
670 | base *b; | |
671 | ... | |
672 | ar & b; | |
673 | } | |
674 | </code></pre> | |
675 | Note that if the serialization function is split between save and load, both | |
676 | functions must include the registration. This is required to keep the save | |
677 | and corresponding load in syncronization. | |
678 | ||
679 | <h4><a name="export">Export</a></h4> | |
680 | The above will work but may be inconvenient. We don't always know which derived | |
681 | classes we are going to serialize when we write the code to serialize through | |
682 | a base class pointer. Every time a new derived class is written we have to | |
683 | go back to all the places where the base class is serialized and update the | |
684 | code. | |
685 | <p> | |
686 | So we have another method: | |
687 | <pre><code> | |
688 | #include <boost/serialization/export.hpp> | |
689 | ... | |
690 | BOOST_CLASS_EXPORT_GUID(derived_one, "derived_one") | |
691 | BOOST_CLASS_EXPORT_GUID(derived_two, "derived_two") | |
692 | ||
693 | main(){ | |
694 | ... | |
695 | base *b; | |
696 | ... | |
697 | ar & b; | |
698 | } | |
699 | </code></pre> | |
700 | The macro <code style="white-space: normal">BOOST_CLASS_EXPORT_GUID</code> associates a string literal | |
701 | with a class. In the above example we've used a string rendering | |
702 | of the class name. If a object of such an "exported" class is serialized | |
703 | through a pointer and is otherwise unregistered, the "export" string is | |
704 | included in the archive. When the archive | |
705 | is later read, the string literal is used to find the class which | |
706 | should be created by the serialization library. | |
707 | This permits each class to be in a separate header file along with its | |
708 | string identifier. There is no need to maintain a separate "pre-registration" | |
709 | of derived classes that might be serialized. This method of | |
710 | registration is referred to as "key export". More information on this | |
711 | topic is found in the section Class Traits - | |
712 | <a target="detail" href="traits.html#export">Export Key</a>. | |
713 | <p> | |
714 | <h4><a name="instantiation">Instantiation</a></h4> | |
715 | Registration by means of any of the above methods fulfill another role | |
716 | whose importance might not be obvious. This system relies on templated | |
717 | functions of the form <code style="white-space: normal">template<class Archive, class T></code>. | |
718 | This means that serialization code must be instantiated for each | |
719 | combination of archive and data type that is serialized in the program. | |
720 | <p> | |
721 | Polymorphic pointers of derived classes may never be referred to | |
722 | explictly by the program so normally code to serialize such classes | |
723 | would never be instantiated. So in addition to including export key | |
724 | strings in an archive, <code style="white-space: normal">BOOST_CLASS_EXPORT_GUID</code> explicitly | |
725 | instantiates the class serialization code for all archive classes used | |
726 | by the program. | |
727 | ||
728 | <h4><a name="selectivetracking">Selective Tracking</a></h4> | |
729 | Whether or not an object is tracked is determined by its | |
730 | <a target="detail" href="traits.html#tracking">object tracking trait</a>. | |
731 | The default setting for user defined types is <code style="white-space: normal">track_selectively</code>. | |
732 | That is, track objects if and only if they are serialized through pointers anywhere | |
733 | in the program. Any objects that are "registered" by any of the above means are presumed | |
734 | to be serialized through pointers somewhere in the program and therefore | |
735 | would be tracked. In certain situations this could lead to an inefficiency. | |
736 | Suppose we have a class module used by multiple programs. Because | |
737 | some programs serializes polymorphic pointers to objects of this class, we | |
738 | <a target="detail" href="traits.html#export">export</a> a class | |
739 | identifier by specifying <code style="white-space: normal">BOOST_CLASS_EXPORT</code> in the | |
740 | class header. When this module is included by another program, | |
741 | objects of this class will always be tracked even though it | |
742 | may not be necessary. This situation could be addressed by using | |
743 | <a target="detail" href="traits.html#tracking"><code style="white-space: normal">track_never</code></a> | |
744 | in those programs. | |
745 | <p> | |
746 | It could also occur that even though a program serializes through | |
747 | a pointer, we are more concerned with efficiency than avoiding the | |
748 | the possibility of creating duplicate objects. It could be | |
749 | that we happen to know that there will be no duplicates. It could | |
750 | also be that the creation of a few duplicates is benign and not | |
751 | worth avoiding given the runtime cost of tracking duplicates. | |
752 | Again, <a target="detail" href="traits.html#tracking"><code style="white-space: normal">track_never</code></a> | |
753 | can be used. | |
754 | <h4><a name="runtimecasting">Runtime Casting</a></h4> | |
755 | In order to properly translate between base and derived pointers | |
756 | at runtime, the system requires each base/derived pair be found | |
757 | in a table. A side effect of serializing a base object with | |
758 | <code style="white-space: normal">boost::serialization::base_object<Base>(Derived &)</code> | |
759 | is to ensure that the base/derived pair is added to the table | |
760 | before the <code style="white-space: normal">main</code> function is entered. | |
761 | This is very convenient and results in a clean syntax. The only | |
762 | problem is that it can occur where a derived class serialized | |
763 | through a pointer has no need to invoke the serialization of | |
764 | its base class. In such a case, there are two choices. The obvious | |
765 | one is to invoke the base class serialization with <code style="white-space: normal">base_object</code> | |
766 | and specify an empty function for the base class serialization. | |
767 | The alternative is to "register" the Base/Derived relationship | |
768 | explicitly by invoking the template | |
769 | <code style="white-space: normal">void_cast_register<Derived, Base>();</code>. | |
770 | Note that this usage of the term "register" is not related | |
771 | to its usage in the previous section. Here is an example of how this is done: | |
772 | <pre><code> | |
773 | #include <sstream> | |
774 | #include <boost/serialization/serialization.hpp> | |
775 | #include <boost/archive/text_iarchive.hpp> | |
776 | #include <boost/serialization/export.hpp> | |
777 | ||
778 | class base { | |
779 | friend class boost::serialization::access; | |
780 | //... | |
781 | // only required when using method 1 below | |
782 | // no real serialization required - specify a vestigial one | |
783 | template<class Archive> | |
784 | void serialize(Archive & ar, const unsigned int file_version){} | |
785 | }; | |
786 | ||
787 | class derived : public base { | |
788 | friend class boost::serialization::access; | |
789 | template<class Archive> | |
790 | void serialize(Archive & ar, const unsigned int file_version){ | |
791 | // method 1 : invoke base class serialization | |
792 | ar & boost::serialization::base_object<base>(*this); | |
793 | // method 2 : explicitly register base/derived relationship | |
794 | boost::serialization::void_cast_register<derived, base>( | |
795 | static_cast<derived *>(NULL), | |
796 | static_cast<base *>(NULL) | |
797 | ) | |
798 | } | |
799 | }; | |
800 | ||
801 | BOOST_CLASS_EXPORT_GUID(derived, "derived") | |
802 | ||
803 | main(){ | |
804 | //... | |
805 | std::stringstream ss; | |
806 | boost::archive::text_iarchive ar(ss); | |
807 | base *b; | |
808 | ar >> b; | |
809 | } | |
810 | </code></pre> | |
811 | <p> | |
812 | ||
813 | In order for this template to be invoked in code compiled by non-conforming | |
814 | compilers, the following syntax may be used: | |
815 | <pre><code> | |
816 | boost::serialization::void_cast_register( | |
817 | static_cast<Derived *>(NULL), | |
818 | static_cast<Base *>(NULL) | |
819 | ); | |
820 | </code></pre> | |
821 | For more information, see <a target="detail" href="implementation.html#tempatesyntax">Template Invocation syntax</a> | |
822 | ||
823 | <h3><a name="references"></a>References</h3> | |
824 | Classes that contain reference members will generally require | |
825 | non-default constructors as references can only be set when | |
826 | an instance is constructed. The example of the previous section | |
827 | is slightly more complex if the class has reference members. | |
828 | This raises the question of how and where the objects being | |
829 | referred to are stored and how are they created. Also there is the question about | |
830 | references to polymorphic base classes. Basically, these | |
831 | are the same questions that arise regarding pointers. This is | |
832 | no surprise as references are really a special kind of pointer. | |
833 | We address these questions by serializing references as though | |
834 | they were pointers. | |
835 | <pre><code> | |
836 | class object; | |
837 | class my_class { | |
838 | private: | |
839 | friend class boost::serialization::access; | |
840 | int member1; | |
841 | object & member2; | |
842 | template<class Archive> | |
843 | void serialize(Archive &ar, const unsigned int file_version); | |
844 | public: | |
845 | my_class(int m, object & o) : | |
846 | member1(m), | |
847 | member2(o) | |
848 | {} | |
849 | }; | |
850 | </code></pre> | |
851 | the overrides would be: | |
852 | <pre><code> | |
853 | namespace boost { namespace serialization { | |
854 | template<class Archive> | |
855 | inline void save_construct_data( | |
856 | Archive & ar, const my_class * t, const unsigned int file_version | |
857 | ){ | |
858 | // save data required to construct instance | |
859 | ar << t.member1; | |
860 | // serialize reference to object as a pointer | |
861 | ar << & t.member2; | |
862 | } | |
863 | ||
864 | template<class Archive> | |
865 | inline void load_construct_data( | |
866 | Archive & ar, my_class * t, const unsigned int file_version | |
867 | ){ | |
868 | // retrieve data from archive required to construct new instance | |
869 | int m; | |
870 | ar >> m; | |
871 | // create and load data through pointer to object | |
872 | // tracking handles issues of duplicates. | |
873 | object * optr; | |
874 | ar >> optr; | |
875 | // invoke inplace constructor to initialize instance of my_class | |
876 | ::new(t)my_class(m, *optr); | |
877 | } | |
878 | }} // namespace ... | |
879 | </code></pre> | |
880 | ||
881 | <h3><a name="arrays"></a>Arrays</h3> | |
882 | If <code style="white-space: normal">T</code> is a serializable type, | |
883 | then any native C++ array of type T is a serializable type. | |
884 | That is, if <code style="white-space: normal">T</code> | |
885 | is a serializable type, then the following | |
886 | is automatically available and will function as expected: | |
887 | <pre><code> | |
888 | T t[4]; | |
889 | ar << t; | |
890 | ... | |
891 | ar >> t; | |
892 | </code></pre> | |
893 | ||
894 | <h2><a href="traits.html">Class Serialization Traits</a></h2> | |
895 | ||
896 | <h2><a href="wrappers.html">Serialization Wrappers</a></h2> | |
897 | ||
898 | <h2><a name="models"></a>Models - Serialization Implementations Included in the Library</h2> | |
899 | The facilities described above are sufficient to implement | |
900 | serialization for all STL containers. In fact, this has been done | |
901 | and has been included in the library. For example, in order to use | |
902 | the included serialization code for <code style="white-space: normal">std::list</code>, use: | |
903 | <pre><code> | |
904 | #include <boost/serialization/list.hpp> | |
905 | </code></pre> | |
906 | rather than | |
907 | <pre><code> | |
908 | #include <list> | |
909 | </code></pre> | |
910 | Since the former includes the latter, this is all that is necessary. | |
911 | The same holds true for all STL collections as well as templates | |
912 | required to support them (e.g. <code style="white-space: normal">std::pair</code>). | |
913 | <p> | |
914 | As of this writing, the library contains serialization of the following boost classes: | |
915 | <ul> | |
916 | <li>optional | |
917 | <li>variant | |
918 | <li>scoped_ptr | |
919 | <li>shared_ptr | |
920 | <li>auto_ptr (demo) | |
921 | </ul> | |
922 | Others are being added to the list so check the boost files section and headers for | |
923 | new implementations! | |
924 | <hr> | |
925 | <p><i>© Copyright <a href="http://www.rrsd.com">Robert Ramey</a> 2002-2004. | |
926 | Distributed under the Boost Software License, Version 1.0. (See | |
927 | accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
928 | </i></p> | |
929 | </body> | |
930 | </html> |