shared_ptr.html 8.8 KB

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