• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 .
5Use, modification and distribution is subject to the Boost Software
6License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7http://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 - Class Serialization Traits</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">Class Serialization Traits</h2>
24    </td>
25  </tr>
26</table>
27<hr>
28<dl class="page-index">
29  <dt><a href="#version">Version</a>
30  <dt><a href="#level">Implementation Level</a>
31  <dt><a href="#tracking">Object Tracking</a>
32  <dt><a href="#export">Export Key</a>
33  <dt><a href="#abstract">Abstract</a>
34  <dt><a href="#typeinfo">Type Information Implementation</a>
35  <dt><a href="#wrappers">Wrappers</a>
36  <dt><a href="#bitwise">Bitwise Serialization</a>
37  <dt><a href="#templates">Template Serialization Traits</a>
38  <dt><a href="#compiletime_messages">Compile Time Warnings and Errors</a>
39</dl>
40Serialization of data depends on the type of the data.  For example, for
41primitive types such as <code style="white-space: normal">int</code>, it wouldn't make sense to save
42a version number in the archive. Likewise, for a data type that is never
43serialized through a pointer, it would (almost) never make sense to track
44the address of objects saved to/loaded from the archive as it will never
45be saved/loaded more than once in any case.  Details of
46serialization for a particular data type will vary depending on the
47type, the way it is used and specifications of the programmer.
48<p>
49One can alter the manner in which a particular data type is serialized
50by specifying one or more <strong>class serialization traits</strong>.
51It is not generally necessary for the programmer to explictly assign
52traits to his classes as there are default values for all traits.
53If the default values are not appropriate they can be assigned by the programmer.
54A template is used to associate a typename with a constant.  For example
55see <a href="../../../boost/serialization/version.hpp" target="version_hpp">
56version.hpp</a>.
57<h3><a name="version">Version</a></h3>
58This header file includes the following code:
59
60<pre><code>
61namespace boost {
62namespace serialization {
63template&lt;class T&gt;
64struct version
65{
66    BOOST_STATIC_CONSTANT(unsigned int, value = 0);
67};
68} // namespace serialization
69} // namespace boost
70</code></pre>
71
72For any class <code style="white-space: normal">T</code>, The default definition
73of <code style="white-space: normal">boost::serialization::version&lt;T&gt;::value</code> is 0.
74If we want to assign a value of 2 as the version for class <code style="white-space: normal">my_class</code>
75we specialize the version template:
76<pre><code>
77namespace boost {
78namespace serialization {
79struct version&lt;my_class&gt;
80{
81    BOOST_STATIC_CONSTANT(unsigned int, value = 2);
82};
83} // namespace serialization
84} // namespace boost
85</code></pre>
86Now whenever the version number for class <code style="white-space: normal">my_class</code> is required,
87the value 2 will be returned rather than the default value of 0.
88<p>
89To diminish typing and enhance readability, a macro is defined
90so that instead of the above, we could write:
91<pre><code>
92BOOST_CLASS_VERSION(my_class, 2)
93</code></pre>
94which expands to the code above.
95
96<h3><a name="level">Implementation Level</a></h3>
97In the same manner as the above, the "level" of implementation of serialization is
98specified.  The header file <a href="../../../boost/serialization/level.hpp"
99target="level_hpp">level.hpp</a> defines the following.
100<pre><code>
101// names for each level
102enum level_type
103{
104    // Don't serialize this type. An attempt to do so should
105    // invoke a compile time assertion.
106    not_serializable = 0,
107    // write/read this type directly to the archive. In this case
108    // serialization code won't be called.  This is the default
109    // case for fundamental types.  It presumes a member function or
110    // template in the archive class that can handle this type.
111    // there is no runtime overhead associated reading/writing
112    // instances of this level
113    primitive_type = 1,
114    // Serialize the objects of this type using the objects "serialize"
115    // function or template. This permits values to be written/read
116    // to/from archives but includes no class or version information.
117    object_serializable = 2,
118    ///////////////////////////////////////////////////////////////////
119    // once an object is serialized at one of the above levels, the
120    // corresponding archives cannot be read if the implementation level
121    // for the archive object is changed.
122    ///////////////////////////////////////////////////////////////////
123    // Add class information to the archive.  Class information includes
124    // implementation level, class version and class name if available.
125    object_class_info = 3,
126};
127</code></pre>
128Using a macro defined in <code style="white-space: normal">level.hpp</code> we can specify
129that <code style="white-space: normal">my_class</code> should be serialized along with its version number:
130<pre><code>
131BOOST_CLASS_IMPLEMENTATION(my_class, boost::serialization::object_class_info)
132</code></pre>
133If implementation level is not explicitly assigned, the system uses
134a default according to the following rules.
135<ul>
136  <li>if the data type is <code style="white-space: normal">volatile</code>
137assign <code style="white-space: normal">not_serializable</code>
138  <li>else if it's an enum or fundamental type assign <code style="white-space: normal">primitive_type</code>
139  <li>else assign <code style="white-space: normal">object_class_info</code>
140</ul>
141That is, for most user defined types, objects will be serialized along with
142class version information. This will permit one to maintain backward
143compatibility with archives which contain previous versions.  However, with this
144ability comes a small runtime cost.  For types whose definition will "never"
145change, efficiency can be gained by specifying <code style="white-space: normal">object_serializable</code>
146to override the default setting of <code style="white-space: normal">object_class_info</code>.
147For example,
148this has been done for the
149<a href="../../../boost/serialization/binary_object.hpp" target="binary_object_hpp">
150binary_object wrapper</a>
151
152<h3><a name="tracking">Object Tracking</a></h3>
153Depending on the way a type is used, it may be necessary or convenient to
154track the address of objects saved and loaded.  For example, this is generally
155necessary while serializing objects through a pointer in order to be sure
156that multiple identical objects are not created when an archive is loaded.
157This "tracking behavior" is controlled by the type trait defined in the header
158file <a href="../../../boost/serialization/tracking.hpp" target="tracking_hpp">tracking.hpp</a>
159which defines the following:
160<pre><code>
161// names for each tracking level
162enum tracking_type
163{
164    // never track this type
165    track_never = 0,
166    // track objects of this type if the object is serialized through a
167    // pointer.
168    track_selectively = 1,
169    // always track this type
170    track_always = 2
171};
172</code></pre>
173A corresponding macro is defined so that we can use:
174<pre><code>
175BOOST_CLASS_TRACKING(my_class, boost::serialization::track_never)
176</code></pre>
177Default tracking traits are:
178<ul>
179  <li>For primitive, <code style="white-space: normal">track_never</code>.
180  <li>For pointers, <code style="white-space: normal">track_never</code>.
181  That is, addresses of addresses are not tracked by default.
182  <li>All current serialization wrappers such as <code style="white-space: normal">boost::serialization::nvp</code>,
183  <code style="white-space: normal">track_never</code>.
184  <li>For all other types, <code style="white-space: normal">track_selectively</code>.
185  That is addresses of serialized objects are tracked if and only if
186  one or more of the following is true:
187  <ul>
188  <li>an object of this type is anywhere in the program serialized
189  through a pointer.
190  <li>the class is explicitly "exported" - see below.
191  <li>the class is explicitly "registered" in the archive
192  </ul>
193</ul>
194
195<p>
196The default behavior is almost always the most convenient one.  However,
197there a few cases where it would be desirable to override the
198default.  One case is that of a virtual base class. In a diamond
199heritance structure with a virtual base class, object tracking
200will prevent redundant save/load invocations.  So here is one
201case where it might be convenient to override the default tracking
202trait. <i>(Note: in a future version the default will be reimplemented
203to automatically track classes used as virtual bases).</i> This
204situation is demonstrated by
205<a href="../test/test_diamond.cpp" target="test_diamond_cpp">test_diamond.cpp</a>
206included with the library.
207
208<h3><a name="export">Export Key</a></h3>
209
210When serializing a derived class through a virtual base class pointer,
211two issues may arise.
212<ul>
213<li> The code in the derived class might never be explicitly
214referred to.  Such code will never be instantiated.
215<p>
216This is addressed by invoking
217<code style="white-space: normal">BOOST_CLASS_EXPORT_IMPLEMENT(T)</code>
218in the file which defines (implements) the class T.
219This ensures that code for the derived class T will
220be explicity instantiated.
221<li> There needs to be some sort of identifier which can
222be used to select the code to be invoked when the object
223is loaded.
224Standard C++ does implement <code style="white-space: normal">typeid()</code> which can be
225used to return a unique string for the class.  This is not entirely
226statisfactory for our purposes for the following reasons:
227<ul>
228  <li>There is no guarantee that the string is the same across platforms.
229  This would then fail to support portable archives.
230  <li>In using code modules from various sources, classes may have
231  to be wrapped in different namespaces in different programs.
232  <li>There might be classes locally defined in different code modules
233  that have the same name.
234  <li>There might be classes with different names that we want to
235  consider equivalent for purposes of serialization.
236</ul>
237<p>
238So in the serialization library, this is addressed by invoking
239<code style="white-space: normal">BOOST_CLASS_EXPORT_KEY2(my_class, "my_class_external_identifier")</code>
240in the header file which declares the class.
241In a large majority of applications, the class name works just fine
242for the external identifier string so the following short cut is
243defined -
244<code style="white-space: normal">BOOST_CLASS_EXPORT_KEY(my_class)</code>.
245</ul>
246For programs which consist of only one module - that is
247programs which do not use DLLS, one can specify
248<code style="white-space: normal">BOOST_CLASS_EXPORT(my_class)</code>
249or
250<code style="white-space: normal">BOOST_CLASS_EXPORT_GUID(my_class, "my_class_external_identifier")</code>
251in either the declaration header or definition.  These macros
252expand to invocation of both of the macros described above.
253<i>(<b>GUID</b> stands for <b>G</b>lobally <b>U</b>nique <b>ID</b>entfier.)</i>
254<p>
255<i>(<a target="detail" href="special.html#export">Elsewhere</a>
256in this manual, the serialization of derived classes is addressed in detail.)</i>
257<p>
258The header file
259<a href="../../../boost/serialization/export.hpp" target="export_hpp">export.hpp</a>
260contains all macro definitions described here.
261The library will throw a runtime exception if
262<ul>
263<li> A type not explicitly referred to is not exported.
264<li> Serialization code for the same type is instantiated
265in more than one module (or DLL).
266</ul>
267
268<h3><a name="abstract">Abstract</a></h3>
269When serializing an object through a pointer to its base class,
270the library needs to determine whether or not the base is abstract
271(i.e. has at least one virtual function).  The library uses the
272type trait macro <code style="white-space: normal">BOOST_IS_ABSTRACT(T)</code>
273to do this.  Not all compilers support this type trait and corresponding
274macro.  To address this, the macro <code style="white-space: normal">
275BOOST_SERIALIZATION_ASSUME_ABSTRACT(T)</code> has been
276implemented to permit one to explicitly indicate that a specified
277type is in fact abstract.  This will guarentee that
278<code style="white-space: normal">BOOST_IS_ABSTRACT</code>
279will return the correct value for all compilers.
280
281<h3><a name="typeinfo">Type Information Implementation</a></h3>
282This last trait is also related to the serialization of objects
283through a base class pointer.  The implementation of this facility
284requires the ability to determine at run time the true type of the
285object that a base class pointer points to.  Different serialization
286systems do this in different ways.  In our system, the default method
287is to use the function <code style="white-space: normal">typeid(...)</code> which is available
288in systems which support <b>RTTI</b> (<b>R</b>un <b>T</b>ime
289<b>T</b>ype <b>I</b>nformation).
290This will be satisfactory in almost all cases and most users of this
291library will lose nothing in skipping this section of the manual.
292<p>
293However, there are some cases where the default type determination
294system is not convenient.  Some platforms might not support
295RTTI or it may have been disabled in order to speed execution
296or for some other reason.  Some applications, E.G. runtime linking
297of plug-in modules, can't depend on C++ RTTI to determine the
298true derived class.  RTTI only returns the correct type for polymorphic
299classes - classes with at least one virtual function.  If any of these
300situations applies, one may substitute his own implementation of
301<code style="white-space: normal">extended_type_info</code>
302<p>
303The interface to facilities required to implement serialization is defined in
304<a href="../../../boost/serialization/extended_type_info.hpp"
305target="extended_type_info_hpp">extended_type_info.hpp</a>.
306
307Default implementation of these facilities based on <code style="white-space: normal">typeid(...)</code>
308is defined in
309
310<a href="../../../boost/serialization/extended_type_info_typeid.hpp"
311target="extended_type_info_typeid_hpp">extended_type_info_typeid.hpp</a>.
312
313An alternative implementation based on exported class identifiers
314is defined in
315<a href="../../../boost/serialization/extended_type_info_no_rtti.hpp"
316target="extended_type_info_rtti_hpp">extended_type_info_no_rtti.hpp</a>.
317<p>
318By invoking the macro:
319<pre><code>
320BOOST_CLASS_TYPE_INFO(
321    my_class,
322    extended_type_info_no_rtti&lt;my_class&gt;
323)
324</code></pre>
325we can assign the type information implementation to each class on a case by
326case basis.  There is no requirement that all classes in a program use the same
327implementation of <code style="white-space: normal">extended_type_info</code>.  This supports the concept
328that serialization of each class is specified "once and for all" in a header
329file that can be included in any project without change.
330<p>
331This is illustrated by the test program
332<a href="../test/test_no_rtti.cpp" target="test_no_rtti_cpp">test_no_rtti.cpp</a>.
333Other implementations are possible and might be necessary for
334certain special cases.
335
336<h3><a name="wrappers">Wrappers</a></h3>
337Archives need to treat wrappers differently from other types since, for example,
338they usually are non-const objects while output archives require that any
339serialized object (with the exception of a wrapper) be const.
340
341This header file <a href="../../../boost/serialization/wrapper.hpp">wrapper.hpp</a>
342includes the following code:
343
344<pre><code>
345namespace boost {
346namespace serialization {
347template&lt;class T&gt;
348struct is_wrapper
349 : public mpl::false_
350{};
351} // namespace serialization
352} // namespace boost
353</code></pre>
354
355For any class <code style="white-space: normal">T</code>, The default definition
356of <code style="white-space: normal">boost::serialization::is_wrapper&lt;T&gt;::value</code> is thus false.
357
358If we want to declare that a class <code style="white-space: normal">my_class</code>
359is a wrapper we specialize the version template:
360<pre><code>
361namespace boost {
362namespace serialization {
363struct is_wrapper&lt;my_class&gt;
364 : mpl::true_
365{};
366} // namespace serialization
367} // namespace boost
368</code></pre>
369<p>
370To diminish typing and enhance readability, a macro is defined
371so that instead of the above, we could write:
372<pre><code>
373BOOST_CLASS_IS_WRAPPER(my_class)
374</code></pre>
375which expands to the code above.
376
377<h3><a name="bitwise">Bitwise Serialization</a></h3>
378Some simple classes could be serialized just by directly copying all bits
379of the class. This is, in particular, the case for POD data types containing
380no pointer members, and which are neither versioned nor tracked. Some archives,
381such as non-portable binary archives can make us of this information to
382substantially speed up serialization.
383
384To indicate the possibility of bitwise serialization the type trait defined
385in the header
386file <a href="../../../boost/serialization/is_bitwise_serializable.hpp" target="is_bitwise_serializable">is_bitwise_serializable.hpp</a>
387is used:
388<pre><code>
389namespace boost { namespace serialization {
390    template<class T>
391    struct is_bitwise_serializable
392     : public is_arithmetic<T>
393    {};
394} }
395</code></pre>
396is used, and can be specialized for other classes. The specialization
397is made easy by the corresponding macro:
398<pre><code>
399BOOST_IS_BITWISE_SERIALIZABLE(my_class)
400</code></pre>
401
402<h3><a name="templates">Template Serialization Traits</a></h3>
403In some instances it might be convenient to assign serialization traits
404to a whole group of classes at once.  Consider, the name-value pair
405wrapper
406<pre><code>
407template&lt;class T&gt;
408struct nvp : public std::pair&lt;const char *, T *&gt;
409{
410    ...
411};
412</code></pre>
413used by XML archives to associate a name with a data variable of type T.
414These data types are never tracked and never versioned.  So one might
415want to specify:
416<pre><code>
417BOOST_CLASS_IMPLEMENTATION(nvp&lt;T&gt;, boost::serialization::level_type::object_serializable)
418BOOST_CLASS_TRACKING(nvp&lt;T&gt;, boost::serialization::track_never)
419</code></pre>
420Examination of the definition of these macros reveals that they won't expand
421to sensible code when used with a template argument.  So rather than using the
422convenience macros, use the original definitions
423<pre><code>
424template&lt;class T&gt;
425struct implementation_level&lt;nvp&lt;T&gt; &gt;
426{
427    typedef mpl::integral_c_tag tag;
428    typedef mpl::int_&lt;object_serializable&gt; type;
429    BOOST_STATIC_CONSTANT(
430        int,
431        value = implementation_level::type::value
432    );
433};
434
435// nvp objects are generally created on the stack and are never tracked
436template&lt;class T&gt;
437struct tracking_level&lt;nvp&lt;T&gt; &gt;
438{
439    typedef mpl::integral_c_tag tag;
440    typedef mpl::int_&lt;track_never&gt; type;
441    BOOST_STATIC_CONSTANT(
442        int,
443        value = tracking_level::type::value
444    );
445};
446</code></pre>
447to assign serialization traits to all classes generated by the template
448<code style="white-space: normal">nvp&lt;T&gt;</code>
449<p>
450
451Note that it is only possible to use the above method to assign traits to
452templates when using compilers which correctly support Partial Template Specialization.
453
454One's first impulse might be to do something like:
455
456<pre><code>
457#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
458template&lt;class T&gt;
459struct implementation_level&lt;nvp&lt;T&gt; &gt;
460{
461   ... // see above
462};
463
464// nvp objects are generally created on the stack and are never tracked
465template&lt;class T&gt;
466struct tracking_level&lt;nvp&lt;T&gt; &gt;
467{
468   ... // see above
469};
470#endif
471</code></pre>
472This can be problematic when one wants to make his code <strong>and archives</strong>
473portable to other platforms.  It means the objects will be serialized differently
474depending on the platform used.  This implies that objects saved from one platform
475won't be loaded properly on another.  In other words, archives won't be portable.
476<p>
477This problem is addressed by creating another method of assigning serialization traits
478to user classes.  This is illustrated by the serialization for a
479<a target="nvp" href="../../../boost/serialization/nvp.hpp"><strong>name-value</strong> pair</a>.
480<p>
481Specifically, this entails deriving the template from a special class
482<a target="traits" href="../../../boost/serialization/traits.hpp">
483<code style="white-space: normal">boost::serialization::traits</code></a> which is specialized for a specific
484combination of serialization traits.
485When looking up the serialization traits, the library first checks to see if this class has been
486used as a base class. If so, the corresponding traits are used.  Otherwise, the standard defaults
487are used. By deriving from a serialization traits class rather than relying upon Partial Template
488Specializaton, one can a apply serialization traits to a template and those traits will be
489the same across all known platforms.
490<p>
491The signature for the traits template is:
492<pre><code>
493template&lt;
494    class T,
495    int Level,
496    int Tracking,
497    unsigned int Version = 0,
498    class ETII = BOOST_SERIALIZATION_DEFAULT_TYPE_INFO(T),
499    class IsWrapper = mpl::false_
500&gt;
501struct traits
502</code></pre>
503and template parameters should be assigned according to the following table:
504<p>
505<table border>
506<tr><th align=left>parameter</th><th align=left>description</th><th align=left>permitted values</th><th align=left>default value</th></tr>
507<tr><td><code>T</code></td><td>target class</td><td>class name<T></td><td>none</td></tr>
508<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>
509<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>
510<tr><td><code>Version</code></td><td><code>class version</td><td>unsigned integer</td><td><code>0</code></td></tr>
511<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>
512<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>
513</table>
514
515<h3><a name="compiletime_messages">Compile Time Warnings and Errors</a></h3>
516Some serialization traits can conflict with other ones.  Sometimes these conflicts
517will result in erroneous behavior (E.G. creating of archives which could not be read)
518and other times they represent a probable misconception on the part of the
519library user which could result in suprising behavior.  To the extent possible,
520these conflicts are detected at compile time and errors (BOOST_STATIC_ASSERT)
521or warnings (BOOST_STATIC_WARNING) are generated. They are generated in a
522compiler dependent manner which should show a chain of instantiation
523to the point where the error/warning is detected.  Without this capability,
524it would be very hard to track down errors or unexpected behavior in library
525usage.  Here is a list of the conflicts trapped:
526
527<dl>
528<dt><h2><a name="object_level">object_level</a> - error</h2></dt>
529<dd>
530This error traps attempts to serialize types whose
531implentation level is set to non_serializable.
532</dd>
533<dt><h2><a name="object_versioning">object_versioning</a> - error</h2></dt>
534<dd>
535It's possible that for efficiency reasons, a type can be
536assigned a serialization level which doesn't include type information
537in the archive.  This would preclude the assignment
538of a new version number to the type.  This error
539traps attempts to assign a version number in this case.
540This has to be a user error.
541</dd>
542
543<dt><h2><a name="object_tracking">object_tracking</a> - warning</h2></dt>
544<dd>
545The following code will display a message when compiled:
546
547<code style="white-space: normal"><pre>
548T t;
549ar &lt;&lt; t;
550</pre></code>
551
552unless the tracking_level serialization trait is set to "track_never". The following
553will compile without problem:
554
555<code style="white-space: normal"><pre>
556const T t
557ar &lt;&lt; t;
558</pre></code>
559
560Likewise, the following code will trap at compile time:
561
562<code style="white-space: normal"><pre>
563T * t;
564ar >> t;
565</pre></code>
566
567if the tracking_level serialization trait is set to "track_never".
568<p>
569
570The following case illustrates the function of this message.
571It was originally used as an example in the
572mailing list by Peter Dimov.
573
574<code style="white-space: normal"><pre>
575class construct_from
576{
577    ...
578};
579
580void main(){
581    ...
582    Y y;
583    construct_from x(y);
584    ar &lt;&lt; x;
585}
586</pre></code>
587
588Suppose that the above message is not displayed and the code is used as is.
589<ol>
590  <li>this example compiles and executes fine. No tracking is done because
591  construct_from has never been serialized through a pointer. Now some time
592  later, the next programmer(2) comes along and makes an enhancement. He
593  wants the archive to be sort of a log.
594
595<code style="white-space: normal"><pre>
596void main(){
597    ...
598    Y y;
599    construct_from x(y);
600    ar &lt;&lt; x;
601    ...
602    x.f(); // change x in some way
603   ...
604    ar &lt;&lt; x
605}
606</pre></code>
607  <p>
608  Again no problem. He gets two different of copies in the archive, each one is different.
609  That is he gets exactly what he expects and is naturally delighted.
610  <p>
611  <li>Now sometime later, a third programmer(3) sees construct_from and says -
612  oh cool, just what I need. He writes a function in a totally disjoint
613  module. (The project is so big, he doesn't even realize the existence of
614  the original usage) and writes something like:
615
616<code style="white-space: normal"><pre>
617class K {
618    shared_ptr &lt;construct_from&gt; z;
619    template &lt;class Archive&gt;
620    void serialize(Archive & ar, const unsigned version){
621        ar &lt;&lt; z;
622    }
623};
624</pre></code>
625
626  <p>
627  He builds and runs the program and tests his new functionality. It works
628  great and he's delighted.
629  <p>
630  <li>Things continue smoothly as before.  A month goes by and it's
631  discovered that when loading the archives made in the last month (reading the
632  log). Things don't work. The second log entry is always the same as the
633  first. After a series of very long and increasingly acrimonius email exchanges,
634it's discovered
635  that programmer(3) accidently broke programmer(2)'s code .This is because by
636  serializing via a pointer, the "log" object is now being tracked.  This is because
637  the default tracking behavior is "track_selectively".  This means that class
638  instances are tracked only if they are serialized through pointers anywhere in
639  the program. Now multiple saves from the same address result in only the first one
640  being written to the archive. Subsequent saves only add the address - even though the
641  data might have been changed.  When it comes time to load the data, all instances of the log record show the same data.
642  In this way, the behavior of a functioning piece of code is changed due the side
643  effect of a change in an otherwise disjoint module.
644  Worse yet, the data has been lost and cannot be recovered from the archives.
645  People are really upset and disappointed with boost (at least the serialization system).
646  <p>
647  <li>
648  After a lot of investigation, it's discovered what the source of the problem is
649  and class construct_from is marked "track_never" by including:
650<code style="white-space: normal"><pre>
651BOOST_CLASS_TRACKING(construct_from, track_never)
652</pre></code>
653  <li>Now everything works again. Or - so it seems.
654  <p>
655  <li><code style="white-space: normal">shared_ptr&lt;construct_from&gt;</code>
656is not going to have a single raw pointer shared amongst the instances. Each loaded
657<code style="white-space: normal">shared_ptr&lt;construct_from&gt;</code> is going to
658have its own distinct raw pointer. This will break
659<code style="white-space: normal">shared_ptr</code> and cause a memory leak.  Again,
660The cause of this problem is very far removed from the point of discovery.  It could
661well be that the problem is not even discovered until after the archives are loaded.
662Now we not only have a difficult to find and fix program bug, but we have a bunch of
663invalid archives and lost data.
664</ol>
665
666<p>Now consider what happens when the message is displayed:
667
668<ol>
669  <p>
670  <li>Right away, the program traps at
671<code style="white-space: normal"><pre>
672ar &lt;&lt; x;
673</pre></code>
674  <p>
675  <li>The programmer curses (another %^&*&* hoop to jump through). He's in a
676  hurry (and who isn't) and would prefer not to <code style="white-space: normal">const_cast</code>
677  - because it looks bad.  So he'll just make the following change an move on.
678<code style="white-space: normal"><pre>
679Y y;
680const construct_from x(y);
681ar &lt;&lt; x;
682</pre></code>
683  <p>
684  Things work fine and he moves on.
685  <p>
686  <li>Now programer (2) wants to make his change - and again another
687  annoying const issue;
688<code style="white-space: normal"><pre>
689Y y;
690const construct_from x(y);
691...
692x.f(); // change x in some way ; compile error f() is not const
693...
694ar &lt;&lt; x
695</pre></code>
696  <p>
697  He's mildly annoyed now he tries the following:
698  <ul>
699    <li>He considers making f() a const - but presumably that shifts the const
700    error to somewhere else. And he doesn't want to fiddle with "his" code to
701    work around a quirk in the serializaition system
702    <p>
703    <li>He removes the <code style="white-space: normal">const</code>
704    from <code style="white-space: normal">const construct_from</code> above - damn now he
705    gets the trap. If he looks at the comment code where the
706    <code style="white-space: normal">BOOST_STATIC_ASSERT</code>
707    occurs, he'll do one of two things
708    <ol>
709      <p>
710      <li>This is just crazy. Its making my life needlessly difficult and flagging
711      code that is just fine. So I'll fix this with a <code style="white-space: normal">const_cast</code>
712      and fire off a complaint to the list and mabe they will fix it.
713      In this case, the story branches off to the previous scenario.
714      <p>
715      <li>Oh, this trap is suggesting that the default serialization isn't really
716      what I want. Of course in this particular program it doesn't matter. But
717      then the code in the trap can't really evaluate code in other modules (which
718      might not even be written yet). OK, I'll add the following to my
719      construct_from.hpp to solve the problem.
720<code style="white-space: normal"><pre>
721BOOST_CLASS_TRACKING(construct_from, track_never)
722</pre></code>
723    </ol>
724  </ul>
725  <p>
726  <li>Now programmer (3) comes along and make his change. The behavior of the
727  original (and distant module) remains unchanged because the
728  <code style="white-space: normal">construct_from</code> trait has been set to
729  "track_never" so he should always get copies and the log should be what we expect.
730  <p>
731  <li>But now he gets another trap - trying to save an object of a
732  class marked "track_never" through a pointer. So he goes back to
733  construct_from.hpp and comments out the
734  <code style="white-space: normal">BOOST_CLASS_TRACKING</code> that
735  was inserted. Now the second trap is avoided, But damn - the first trap is
736  popping up again. Eventually, after some code restructuring, the differing
737  requirements of serializating <code style="white-space: normal">construct_from</code>
738  are reconciled.
739</ol>
740Note that in this second scenario
741<ul>
742  <li>all errors are trapped at compile time.
743  <li>no invalid archives are created.
744  <li>no data is lost.
745  <li>no runtime errors occur.
746</ul>
747
748It's true that these messages may sometimes flag code that is currently correct and
749that this may be annoying to some programmers.  However, this example illustrates
750my view that these messages are useful and that any such annoyance is a small price to
751pay to avoid particularly vexing programming errors.
752
753</dd>
754
755<dt><h2><a name="pointer_level">pointer_level</a> - warning</h2></dt>
756<dd>
757This trap addresses the following situaion when serializing
758a pointer:
759<ul>
760<li>A type doesn't save class information in the
761archive. That is, the serialization trait implementation
762level <= object_serializable.
763<li>Tracking for this type is set to "track selectively"
764in this case, indication that an object is tracked is
765not stored in the archive itself - see level == object_serializable.
766Since class information is not saved in the archive, the existence
767or absence of the operation ar << T * anywhere else in the
768program is used to infer that an object of this type should be tracked.
769<p>
770A problem arises when a program which reads an archive
771includes the operation ar >> T * so that tracking information
772will be included in the archive. When a program which
773creates the archive doesn't include ar << T it is presumed
774that the archive doesn't include tracking information and
775the archive will fail to load.  Also the reverse situation could
776trigger a similar problem.
777<p>
778Though this situation is unlikely for several reasones,
779it is possible - hence this warning.
780</ul>
781So if your program traps here, consider changing the
782tracking or implementation level traits - or not
783serializing via a pointer.
784</dd>
785
786<dt><h2><a name="pointer_tracking">pointer_tracking</a> - warning</h2></dt>
787<dd>
788Serializing an object of a type marked "track_never" through a pointer
789could result in creating more objects than were saved! There are cases
790in which a user might really want to do this so we leave it as a warning.
791</dd>
792
793<dt><h2><a name="const_loading">const_loading</a> - error</h2></dt>
794<dd>
795One cannot load data into a "const" object unless it's a
796wrapper around some other non-const object.
797</dd>
798</dl>
799
800<hr>
801<p><i>&copy; Copyright <a href="http://www.rrsd.com">Robert Ramey</a> 2002-2004 and Matthias Troyer 2006.
802Distributed under the Boost Software License, Version 1.0. (See
803accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
804</i></p>
805</body>
806</html>
807