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>Template serialization - shared_ptr</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">Template serialization - <code style="white-space: normal">shared_ptr<class T></code></h2> 24 </td> 25 </tr> 26</table> 27<hr> 28All the code snippets included below are defined within the 29<code style="white-space: normal">boost::serialization</code> namespace. 30<p> 31<code style="white-space: normal">shared_ptr<T></code> is defined in 32<a href="../../../boost/shared_ptr.hpp" target=shared_ptr.hpp>shared_ptr.hpp</a>. 33<p> 34The general class outline for a <code style="white-space: normal">shared_ptr<T></code> is: 35<dl> 36 <dt><code style="white-space: normal">shared_ptr<T></code> contains: 37 <dl> 38 <dt><code style="white-space: normal">T *px;</code> 39 <dt><code style="white-space: normal">shared_count pn;</code> which contains a pointer to: 40 <dl> 41 <dt><code style="white-space: normal">sp_counted_base_impl<T, ...></code> which is 42derived from the polymorphic abstract class 43 <dl> 44 <dt><code style="white-space: normal">sp_counted_base</code> 45 </dl> 46 </dl> 47 </dl> 48</dl> 49The serialization process proceeds down the tree above. 50<p> 51The first cut at implementing serialization for <code style="white-space: normal">shared_ptr</code> 52just serializes the relevant members of <code style="white-space: normal">shared_ptr</code>. 53It's almost trivial: 54<pre><code> 55template<class Archive, class T> 56inline void serialize( 57 Archive & ar, 58 shared_ptr<T> & t, 59 const unsigned int file_version, 60 int 61){ 62 ar & t.px; // save the raw pointer 63 ar & t.pn; // save the shared reference count 64} 65</code></pre> 66So far so good. Now for the serialization of <code style="white-space: normal">shared_count</code>: 67<pre><code> 68template<class Archive> 69inline void save( 70 Archive & ar, 71 const boost::detail::shared_count & t, 72 const unsigned int file_version 73){ 74 ar << t.pi_; 75} 76 77template<class Archive> 78inline void load( 79 Archive & ar, 80 boost::detail::shared_count & t, 81 const unsigned int file_version 82){ 83 ar >> t.pi_; 84} 85</code></pre> 86A key feature of this library is the ability to specify serialization 87of a class or template without changing the class or template declaration 88or definition. This is referred to as <i>non-intrusive</i> serialization. 89<p> 90The <code style="white-space: normal">pi_</code>member of shared count is a pointer to an 91instance of <code style="white-space: normal">sp_counted_base_impl<T, ...></code>. Since this class 92doesn't have a default constructor, serialization requires 93specification of the following overload: 94<pre><code> 95template<class Archive, class P, class D> 96inline void save_construct_data( 97 Archive & ar, 98 const boost::detail::sp_counted_base_impl<P, D> * t, 99 const unsigned int file_version 100){ 101 // variables used for construction 102 ar << t->ptr; 103 ar << *t; 104} 105 106template<class Archive, class P, class D> 107inline void load_construct_data( 108 Archive & ar, 109 boost::detail::sp_counted_base_impl<P, D> * t, 110 const unsigned int file_version 111){ 112 P ptr_; 113 ar >> ptr_; 114 // placement new 115 ::new(t)boost::detail::sp_counted_base_impl<P, D>(ptr_, D()); 116 ar >>; *t; 117} 118</code></pre> 119The statement <code style="white-space: normal">ar >> ptr_</code> is key. This deserializes 120the same pointer deserialzed above. Default object tracking will ensure 121that no more than one instance of the object is created and that the 122pointer returned by multiple deserializations are all the same. Hence, 123regardless of how many instances of <code style="white-space: normal">shared_ptr/shared_count</code> 124corresponding to a particular object are created, they will all point 125to the same object. 126<p> 127Since <code style="white-space: normal">sp_counted_base_impl<P, D></code> is derived from 128<code style="white-space: normal">sp_counted_base</code>, the following is needed: 129 130<pre><code> 131template<class Archive, class P, class D> 132inline void serialize( 133 Archive & ar, 134 boost::detail::sp_counted_base_impl<P, D> & t, 135 const unsigned int file_version, 136 int 137){ 138 ar & boost::serialization::base_object< 139 boost::detail::sp_counted_base 140 >(*this); 141} 142</code></pre> 143which will in turn require serialization of its base class: 144<pre><code> 145inline void serialize( 146 Archive & ar, 147 boost::detail::sp_counted & t, 148 const unsigned int file_version, 149 int 150){ 151} 152</code></pre> 153It would seem we're done, but running the test program, 154<a href="../example/demo_shared_ptr.cpp" target="demo_shared_ptr_cpp"> 155demo_shared_ptr.cpp 156</a>, 157with this code produces the following output. 158<pre><code> 159a = 0x003017A0 use count = 2 160a1 = 0x003017A0 use count = 2 161unique element count = 1 162a = 0x00000000 use count = 0 163a1 = 0x00000000 use count = 0 164unique element count = 0 165a = 0x00303060 use count = 1 166a1 = 0x00303060 use count = 1 167unique element count = 1 168</code></pre> 169This indicates that we're not quite done. Due to default object 170tracking, <code style="white-space: normal">sp_counted_base_impl<P, D></code> is only 171created once regardless of how many shared pointers point to the 172same object. Of course, it has to be this way. The reference 173count starts at 1 and is never incrememented. Code must be added 174to the serialization functions to maintain the proper reference 175count. 176<p> 177The process of serialization of an empty base class - 178<code style="white-space: normal">sp_counted_base</code> - seems like additional overhead. 179Examination of code in 180<a href="../../../boost/serialization/base_object.hpp" target="base_object_hpp"> 181base_object.hpp 182</a> 183reveals that <code style="white-space: normal">base_object.hpp</code> provides two functions: 184<ul> 185 <li>invokes serialization of the base class data 186 <li>as a side effect, "registers" the fact base/derived relationship 187so that conversions of pointers between base and derived classes can be 188made at runtime. 189</ul> 190In this case we need only the latter function so we can replace the 191base object serialization with: 192<pre><code> 193// register the relationship between each derived class 194// its polymorphic base 195void_cast_register< 196 boost::detail::sp_counted_base_impl<P, D> 197 boost::detail::sp_counted_base, 198>(); 199</code></pre> 200and we don't have to include a trival serializer for <code style="white-space: normal">sp_counted_base</code>. 201<p> 202Finally we need to specify name-value pair wrappers if we want to be able 203to use this serialization with XML archives. 204<p> 205Actually, even this is really just a start. Among the issues not addressed in 206this implementation are: 207<ul> 208 <li><code style="white-space: normal">weak_ptr</code> is not addressed. I haven't even looked into this. 209 <li>Other smart pointers that might interact with <code style="white-space: normal">shared_ptr</code> 210 haven't been addressed at all. To be confident that the implementation is 211 complete and correct, all these should be addressed as well. 212 <li>Exception handling hasn't been exhaustively considered. 213 <li>Other issues yet to be discovered. 214</ul> 215One thing that has been considered is export of shared_ptr. The header which 216declares shared pointer serialization includes some special macros for exporting 217shared pointers: 218<code><pre> 219BOOST_SHARED_POINTER_EXPORT(T) 220BOOST_SHARED_POINTER_EXPORT_GUID(T, K) 221</pre></code> 222These are specialized versions of the macros used for exporting classes serialized through raw pointers. 223<p> 224Clear, complete, correct and exception safe serialization of smart pointers is going to 225be a challenge. I hope that this implementation provides a useful 226starting point for such an effort. 227<hr> 228<p><i>© Copyright <a href="http://www.rrsd.com">Robert Ramey</a> 2002-2004. 229Distributed under the Boost Software License, Version 1.0. (See 230accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 231</i></p> 232</body> 233</html> 234