File: traits.html

package info (click to toggle)
boost1.35 1.35.0-5
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 203,856 kB
  • ctags: 337,867
  • sloc: cpp: 938,683; xml: 56,847; ansic: 41,589; python: 18,999; sh: 11,566; makefile: 664; perl: 494; yacc: 456; asm: 353; csh: 6
file content (506 lines) | stat: -rw-r--r-- 22,310 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!--
(C) Copyright 2002-4 Robert Ramey - http://www.rrsd.com . 
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="../../../boost.css">
<link rel="stylesheet" type="text/css" href="style.css">
<title>Serialization - Class Serialization Traits</title>
</head>
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary="header">
  <tr> 
    <td valign="top" width="300"> 
      <h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../boost.png" border="0"></a></h3>
    </td>
    <td valign="top"> 
      <h1 align="center">Serialization</h1>
      <h2 align="center">Class Serialization Traits</h2>
    </td>
  </tr>
</table>
<hr>
<dl class="page-index">
  <dt><a href="#version">Version</a>
  <dt><a href="#level">Implementation Level</a>
  <dt><a href="#tracking">Object Tracking</a>
  <dt><a href="#export">Export Key</a>
  <dt><a href="#abstract">Abstract</a>
  <dt><a href="#typeinfo">Type Information Implementation</a>
  <dt><a href="#wrappers">Wrappers</a>
  <dt><a href="#templates">Template Serialization Traits</a>
</dl>
Serialization of data depends on the type of the data.  For example, for
primitive types such as an <code style="white-space: normal">int</code>, it wouldn't make sense to save
a version number in the archive. Likewise, for a data type that is never
serialized through a pointer, it would (almost) never make sense to track
the address of objects saved to/loaded from the archive as it will never
be saved/loaded more than once in any case.  Details of
serialization for a particular data type will vary depending on the
type, the way it is used and specifications of the programmer. 
<p>
One can alter the manner in which a particular data type is serialized
by specifying one or more <strong>class serialization traits</strong>.
It is not generally necessary for the programmer to explictly assign
traits to his classes as there are default values for all traits.
If the default values are not appropriate they can be assigned by the programmer.
A template is used to associate a typename with a constant.  For example
see <a href="../../../boost/serialization/version.hpp" target="version_hpp">
version.hpp</a>.  
<h3><a name="version">Version</a></h3>
This header file includes the following code:

<pre><code>
namespace boost { 
namespace serialization {
template&lt;class T&gt;
struct version
{
    BOOST_STATIC_CONSTANT(unsigned int, value = 0);
};
} // namespace serialization
} // namespace boost
</code></pre>

For any class <code style="white-space: normal">T</code>, The default definition 
of <code style="white-space: normal">boost::serialization::version&lt;T&gt;::value</code> is 0. 
If we want to assign a value of 2 as the version for class <code style="white-space: normal">my_class</code>
we specialize the version template:
<pre><code>
namespace boost { 
namespace serialization {
struct version&lt;my_class&gt;
{
    BOOST_STATIC_CONSTANT(unsigned int, value = 2);
};
} // namespace serialization
} // namespace boost
</code></pre>
Now whenever the version number for class <code style="white-space: normal">my_class</code> is required,
the value 2 will be returned rather than the default value of 0.
<p>
To diminish typing and enhance readability, a macro is defined
so that instead of the above, we could write:
<pre><code>
BOOST_CLASS_VERSION(my_class, 2)
</code></pre>
which expands to the code above.

<h3><a name="level">Implementation Level</a></h3>
In the same manner as the above, the "level" of implementation of serialization is
specified.  The header file <a href="../../../boost/serialization/level.hpp" 
target="level_hpp">level.hpp</a> defines the following.
<pre><code>
// names for each level
enum level_type
{
    // Don't serialize this type. An attempt to do so should
    // invoke a compile time assertion.
    not_serializable = 0,
    // write/read this type directly to the archive. In this case
    // serialization code won't be called.  This is the default
    // case for fundamental types.  It presumes a member function or
    // template in the archive class that can handle this type.
    // there is no runtime overhead associated reading/writing
    // instances of this level
    primitive_type = 1,
    // Serialize the objects of this type using the objects "serialize"
    // function or template. This permits values to be written/read
    // to/from archives but includes no class or version information. 
    object_serializable = 2,
    ///////////////////////////////////////////////////////////////////
    // once an object is serialized at one of the above levels, the
    // corresponding archives cannot be read if the implementation level
    // for the archive object is changed.  
    ///////////////////////////////////////////////////////////////////
    // Add class information to the archive.  Class information includes
    // implementation level, class version and class name if available.
    object_class_info = 3,
};
</code></pre>
Using a macro defined in <code style="white-space: normal">level.hpp</code> we can specify
that <code style="white-space: normal">my_class</code> should be serialized along with its version number:
<pre><code>
BOOST_CLASS_IMPLEMENTATION(my_class, boost::serialization::object_class_info)
</code></pre>
If implementation level is not explicitly assigned, the system uses
a default according to the following rules.
<ul>
  <li>if the data type is <code style="white-space: normal">volatile</code> 
assign <code style="white-space: normal">not_serializable</code>
  <li>else if it's an enum or fundamental type assign <code style="white-space: normal">primitive_type</code>
  <li>else assign <code style="white-space: normal">object_class_info</code>
</ul>
That is, for most user defined types, objects will be serialized along with
class version information. This will permit one to maintain backward
compatibility with archives which contain previous versions.  However, with this 
ability comes a small runtime cost.  For types whose definition will "never" 
change, efficiency can be gained by specifying <code style="white-space: normal">object_serializable</code> 
to override the default setting of <code style="white-space: normal">object_class_info</code>.  
For example, 
this has been done for the  
<a href="../../../boost/serialization/binary_object.hpp" target="binary_object_hpp">
binary_object wrapper</a>

<h3><a name="tracking">Object Tracking</a></h3>
Depending on the way a type is used, it may be necessary or convenient to
track the address of objects saved and loaded.  For example, this is generally
necessary while serializing objects through a pointer in order to be sure
that multiple identical objects are not created when an archive is loaded.
This "tracking behavior" is controlled by the type trait defined in the header
file <a href="../../../boost/serialization/tracking.hpp" target="tracking_hpp">tracking.hpp</a>
which defines the following:
<pre><code>
// names for each tracking level
enum tracking_type
{
    // never track this type
    track_never = 0,
    // track objects of this type if the object is serialized through a 
    // pointer.
    track_selectively = 1,
    // always track this type
    track_always = 2
};
</code></pre>
A corresponding macro is defined so that we can use:
<pre><code>
BOOST_CLASS_TRACKING(my_class, boost::serialization::track_never)
</code></pre>
Default tracking traits are:
<ul>
  <li>For primitive, <code style="white-space: normal">track_never</code>.
  <li>For pointers, <code style="white-space: normal">track_never</code>.
  That is, addresses of addresses are not tracked by default.
  <li>All current serialization wrappers such as <code style="white-space: normal">boost::serialization::nvp</code>,
  <code style="white-space: normal">track_never</code>.
  <li>For all other types, <code style="white-space: normal">track_selectivly</code>.
  That is addresses of serialized objects are tracked if and only if
  one or more of the following is true:
  <ul>
  <li>an object of this type is anywhere in the program serialized
  through a pointer.
  <li>the class is explicitly "exported" - see below.
  <li>the class is explicitly "registered" in the archive
  </ul>
</ul>

<p>
The default behavior is almost always the most convenient one.  However,
there a few cases where it would be desirable to override the
default.  One case is that of a virtual base class. In a diamond
heritance structure with a virtual base class, object tracking
will prevent redundant save/load invocations.  So here is one
case where it might be convenient to override the default tracking
trait. <i>(Note: in a future version the default will be reimplemented
to automatically track classes used as virtual bases).</i> This 
situation is demonstrated by 
<a href="../test/test_diamond.cpp" target="test_diamond_cpp">test_diamond.cpp</a>
included with the library.
<h3><a name="export">Export Key</a></h3>
When serializing a derived class through a base class pointer, it
may be convenient to define an external name by which the
derived class can be identified.  
<i>(<a target="detail" href="special.html#derivedpointers">Elsewhere</a>
in this manual, the
serialization of derived classes is addressed in detail.)</i>
Standard C++ does implement <code style="white-space: normal">typeid()</code> which can be
used to return a unique string for the class.  This is not entirely
statisfactory for our purposes for the following reasons:
<ul>
  <li>There is no guarantee that the string is the same across platforms.
  This would then fail to support portable archives.
  <li>In using code modules from various sources, classes may have
  to be wrapped in different namespaces in different programs.
  <li>There might be classes locally defined in different code modules
  that have the same name. 
  <li>There might be classes with different names that we want to
  consider equivalent for purposes of of serialization.
</ul>
So the header file
<a href="../../../boost/serialization/export.hpp" target="export_hpp">export.hpp</a>
includes macro definitions to specify the external string used
to identify the class. 
<i>(<b>GUID</b> stands for <b>G</b>lobally <b>U</b>nique <b>ID</b>entfier.)</i>
<pre><code>
BOOST_CLASS_EXPORT_GUID(my_class, "my_class_external_identifier")
</code></pre>
In a large majority of applications, the class name works just fine
for the external identifier string so the following short cut is
defined
<pre><code>
BOOST_CLASS_EXPORT(my_class)
</code></pre>
which expands to:
<pre><code>
BOOST_CLASS_EXPORT_GUID(my_class, "my_class")
</code></pre>
If the an external name is required somewhere in the program and none
has been assigned, a static assertion will be invoked.
<h3><a name="abstract">Abstract</a></h3>
When serializing an object through a pointer to its base class
and that base class is abstract (i.e. has at least one virtual function
assigned a value of 0), A compile error will be emitted.  This is
addressable in one over several ways:
<ul>
  <li>remove the =0 in the base classes so that the base class is no
  longer abstract.
  <li>implement is_abstract for your compiler. (code written according to
  the C++ standard is included with this library.  But it is known to fail
  on several compilers.
  <li>use the macro <code style="white-space: normal">BOOST_IS_ABSTRACT(my_class)</code> to indicate
  that the class is an abstract base class.  This will cause the compiler
  to avoid generating code that causes this error.
  This macro must be used in the global namespace, with full namespace 
  qualification of the argument class. 
</ul>
<h3><a name="typeinfo">Type Information Implementation</a></h3>
This last trait is also related to the serialization of objects
through a base class pointer.  The implementation of this facility
requires the ability to determine at run time the true type of the
object that a base class pointer points to.  Different serialization
systems do this in different ways.  In our system, the default method
is to use the function <code style="white-space: normal">typeid(...)</code> which is available 
in systems which support <b>RTTI</b> (<b>R</b>un <b>T</b>ime 
<b>T</b>ype <b>I</b>nformation).
This will be satisfactory in almost all cases and most users of this 
library will lose nothing in skipping this section of the manual.
<p>
However, there are some cases where the default type determination
system is not convenient.  Some platforms might not support
RTTI or it may have been disabled in order to speed execution
or for some other reason.  Some applications, E.G. runtime linking
of plug-in modules, can't depend on C++ RTTI to determine the
true derived class.  RTTI only returns the correct type for polymorphic
classes - classes with at least one virtual function.  If any of these
situations applies, one may substitute his own implementation of
<code style="white-space: normal">extended_type_info</code>
<p>
The interface to facilities required to implement serialization is defined in
<a href="../../../boost/serialization/extended_type_info.hpp" 
target="extended_type_info_hpp">extended_type_info.hpp</a>.

Default implementation of these facilities based on <code style="white-space: normal">typeid(...)</code>
is defined in

<a href="../../../boost/serialization/extended_type_info_typeid.hpp" 
target="extended_type_info_typeid_hpp">extended_type_info_typeid.hpp</a>.

An alternative implementation based on exported class identifiers
is defined in
<a href="../../../boost/serialization/extended_type_info_no_rtti.hpp" 
target="extended_type_info_rtti_hpp">extended_type_info_no_rtti.hpp</a>.
<p>
By invoking the macro:
<pre><code>
BOOST_CLASS_TYPE_INFO(
    my_class, 
    extended_type_info_no_rtti&lt;my_class&gt;
)
</code></pre>
we can assign the type information implementation to each class on a case by
case basis.  There is no requirement that all classes in a program use the same 
implementation of <code style="white-space: normal">extended_type_info</code>.  This supports the concept
that serialization of each class is specified "once and for all" in a header
file that can be included in any project without change.
<p>
This is illustrated by the test program
<a href="../test/test_no_rtti.cpp" target="test_no_rtti_cpp">test_no_rtti.cpp</a>.
Other implementations are possible and might be necessary for
certain special cases.

version.hpp</a>.  
<h3><a name="wrappers">Wrappers</a></h3>
Archives need to treat wrappers diffently from other types since, for example,
they usually are non-const object while output archives require that any
serialized object (with the exception of a wrapper) be const. 

This header file <a href="../../../boost/serialization/wrapper.hpp">wrapper.hpp</a>
includes the following code:

<pre><code>
namespace boost { 
namespace serialization {
template&lt;class T&gt;
struct is_wrapper
 : public mpl::false_
{};
} // namespace serialization
} // namespace boost
</code></pre>

For any class <code style="white-space: normal">T</code>, The default definition 
of <code style="white-space: normal">boost::serialization::is_wrapper&lt;T&gt;::value</code> is thus false.
 
If we want to declare that a class <code style="white-space: normal">my_class</code>
is a wrapper we specialize the version template:
<pre><code>
namespace boost { 
namespace serialization {
struct is_wrapper&lt;my_class&gt;
 : mpl::true_
{};
} // namespace serialization
} // namespace boost
</code></pre>
<p>
To diminish typing and enhance readability, a macro is defined
so that instead of the above, we could write:
<pre><code>
BOOST_CLASS_IS_WRAPPER(my_class)
</code></pre>
which expands to the code above.



<h3><a name="templates">Template Serialization Traits</a></h3>
In some instances it might be convenient to assign serialization traits
to a whole group of classes at once.  Consider, the name-value pair
wrapper 
<pre><code>
template&lt;class T&gt;
struct nvp : public std::pair&lt;const char *, T *&gt;
{
    ...
};
</code></pre>
used by XML archives to associate a name with a data variable of type T.
These data types are never tracked and never versioned.  So one might
want to specify:
<pre><code>
BOOST_CLASS_IMPLEMENTATION(nvp&lt;T&gt;, boost::serialization::level_type::object_serializable)
BOOST_CLASS_TRACKING(nvp&lt;T&gt;, boost::serialization::track_never)
</code></pre>
Examination of the definition of these macros reveals that they won't expand
to sensible code when used with a template argument.  So rather than using the
convenience macros, use the original definitions
<pre><code>
template&lt;class T&gt;
struct implementation_level&lt;nvp&lt;T&gt; &gt;
{
    typedef mpl::integral_c_tag tag;
    typedef mpl::int_&lt;object_serializable&gt; type;
    BOOST_STATIC_CONSTANT(
        int,
        value = implementation_level::type::value
    );
};

// nvp objects are generally created on the stack and are never tracked
template&lt;class T&gt;
struct tracking_level&lt;nvp&lt;T&gt; &gt;
{
    typedef mpl::integral_c_tag tag;
    typedef mpl::int_&lt;track_never&gt; type;
    BOOST_STATIC_CONSTANT(
        int, 
        value = tracking_level::type::value
    );
};
</code></pre>
to assign serialization traits to all classes generated by the template
<code style="white-space: normal">nvp&lt;T&gt;</code>
<p>

Note that it is only possible to use the above method to assign traits to 
templates when using compilers which correctly support Partial Template Specialization.

One's first impulse might be to do something like:

<pre><code>
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template&lt;class T&gt;
struct implementation_level&lt;nvp&lt;T&gt; &gt;
{
   ... // see above
};

// nvp objects are generally created on the stack and are never tracked
template&lt;class T&gt;
struct tracking_level&lt;nvp&lt;T&gt; &gt;
{
   ... // see above
};
#endif
</code></pre>
This can be problematic when one wants to make his code <strong>and archives</strong>
portable to other platforms.  It means the she objects will be serialized differently
depending on the platform used.  This implies that objects saved from one platform
won't be loaded properly on another.  In other words, archives won't be portable.
<p>
This problem is addressed by creating another method of assigning serialization traits
to user classes.  This is illustrated by the serialization for a 
<a target="nvp" href="../../../boost/serialization/nvp.hpp"><strong>name-value</strong> pair</a>.
<p>
Specifically, this entails deriving the template from a special class
<a target="traits" href="../../../boost/serialization/traits.hpp">
<code style="white-space: normal">boost::serialization::traits</code></a> which is specialized for a specific
combination of serialization traits.  
When looking up the serialization traits, the library first checks to see if this class has been
used as a base class. If so, the corresponding traits are used.  Otherwise, the standard defaults
are used. By deriving from a serialization traits class rather than relying upon Partial Template
Specializaton, one can a apply serialization traits to a template and those traits will be
the same across all known platforms.
<p>
The signature for the traits template is:
<pre><code>
template&lt;
    class T,       
    int Level, 
    int Tracking,
    unsigned int Version = 0,
    class ETII = BOOST_SERIALIZATION_DEFAULT_TYPE_INFO(T),
    class IsWrapper = mpl::false_
&gt;
struct traits
</code></pre>
and template parameters should be assigned according to the following table:
<p>
<table border>
<tr><th align=left>parameter</th><th align=left>description</th><th align=left>permitted values</th><th align=left>default value</th></tr>
<tr><td><code>T</code></td><td>target class</td><td>class name<T></td><td>none</td></tr>            
<tr><td><code>Level</code></td><td>implementation level</td><td><code>not_serializable<br>primitive_type<br>object_serializable<br>object_class_info</code></td><td>none</td></tr>  
<tr><td><code>Tracking</code></td><td>tracking level</td><td><code>track_never<br>track_selectivly<br>track_always</code></td><td>none</td></tr>
<tr><td><code>Version</code></td><td><code>class version</td><td>unsigned integer</td><td><code>0</code></td></tr>
<tr><td><code>ETTI</code></td><td><code>type_info</code> implementation</td><td><code>extended_type_info_typeid<br>extended_type_info_no_rtti</code></td><td>default <code>type_info implementation</code></td></tr>
<tr><td><code>IsWrapper</code></td><td><code></code>is the type a wrapper?</td><td><code>mpl::false_<br>mpl::true_</code></td><td><code>mpl::false_</code></td></tr>
</table>


<h3><a name="tracking">Bitwise serialization</a></h3>
Some simple classes could be serialized just by directly copying all bits
of the class. This is, in particular, the case for POD data types containing
no pointer members, and which are neither versioned nor tracked. Some archives, 
such as non-portable binary archives can make us of this information to 
substantially speed up Serialization.

To indicate the possibility of bitwise serialization the type trait defined 
in the header
file <a href="../../../boost/serialization/is_bitwise_serializable.hpp" target="is_bitwise_serializable">is_bitwise_serializable.hpp</a>
is used:
<pre><code>
namespace boost { namespace serialization {
    template<class T>
    struct is_bitwise_serializable
     : public is_arithmetic<T>
    {};
} }
</code></pre>
is used, and can be specialized for other classes. The specialization
is made easy by the corresponding macro:
<pre><code>
BOOST_IS_BITWISE_SERIALIZABLE(my_class)
</code></pre>

<hr>
<p><i>&copy; Copyright <a href="http://www.rrsd.com">Robert Ramey</a> 2002-2004 and Matthias Troyer 2006. 
Distributed under the Boost Software License, Version 1.0. (See
accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</i></p>
</body>
</html>