123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- <!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>Template serialization - shared_ptr</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">Template serialization - <code style="white-space: normal">shared_ptr<class T></code></h2>
- </td>
- </tr>
- </table>
- <hr>
- All the code snippets included below are defined within the
- <code style="white-space: normal">boost::serialization</code> namespace.
- <p>
- <code style="white-space: normal">shared_ptr<T></code> is defined in
- <a href="../../../boost/shared_ptr.hpp" target=shared_ptr.hpp>shared_ptr.hpp</a>.
- <p>
- The general class outline for a <code style="white-space: normal">shared_ptr<T></code> is:
- <dl>
- <dt><code style="white-space: normal">shared_ptr<T></code> contains:
- <dl>
- <dt><code style="white-space: normal">T *px;</code>
- <dt><code style="white-space: normal">shared_count pn;</code> which contains a pointer to:
- <dl>
- <dt><code style="white-space: normal">sp_counted_base_impl<T, ...></code> which is
- derived from the polymorphic abstract class
- <dl>
- <dt><code style="white-space: normal">sp_counted_base</code>
- </dl>
- </dl>
- </dl>
- </dl>
- The serialization process proceeds down the tree above.
- <p>
- The first cut at implementing serialization for <code style="white-space: normal">shared_ptr</code>
- just serializes the relevant members of <code style="white-space: normal">shared_ptr</code>.
- It's almost trivial:
- <pre><code>
- template<class Archive, class T>
- inline void serialize(
- Archive & ar,
- shared_ptr<T> & t,
- const unsigned int file_version,
- int
- ){
- ar & t.px; // save the raw pointer
- ar & t.pn; // save the shared reference count
- }
- </code></pre>
- So far so good. Now for the serialization of <code style="white-space: normal">shared_count</code>:
- <pre><code>
- template<class Archive>
- inline void save(
- Archive & ar,
- const boost::detail::shared_count & t,
- const unsigned int file_version
- ){
- ar << t.pi_;
- }
- template<class Archive>
- inline void load(
- Archive & ar,
- boost::detail::shared_count & t,
- const unsigned int file_version
- ){
- ar >> t.pi_;
- }
- </code></pre>
- A key feature of this library is the ability to specify serialization
- of a class or template without changing the class or template declaration
- or definition. This is referred to as <i>non-intrusive</i> serialization.
- <p>
- The <code style="white-space: normal">pi_</code>member of shared count is a pointer to an
- instance of <code style="white-space: normal">sp_counted_base_impl<T, ...></code>. Since this class
- doesn't have a default constructor, serialization requires
- specification of the following overload:
- <pre><code>
- template<class Archive, class P, class D>
- inline void save_construct_data(
- Archive & ar,
- const boost::detail::sp_counted_base_impl<P, D> * t,
- const unsigned int file_version
- ){
- // variables used for construction
- ar << t->ptr;
- ar << *t;
- }
- template<class Archive, class P, class D>
- inline void load_construct_data(
- Archive & ar,
- boost::detail::sp_counted_base_impl<P, D> * t,
- const unsigned int file_version
- ){
- P ptr_;
- ar >> ptr_;
- // placement new
- ::new(t)boost::detail::sp_counted_base_impl<P, D>(ptr_, D());
- ar >>; *t;
- }
- </code></pre>
- The statement <code style="white-space: normal">ar >> ptr_</code> is key. This deserializes
- the same pointer deserialzed above. Default object tracking will ensure
- that no more than one instance of the object is created and that the
- pointer returned by multiple deserializations are all the same. Hence,
- regardless of how many instances of <code style="white-space: normal">shared_ptr/shared_count</code>
- corresponding to a particular object are created, they will all point
- to the same object.
- <p>
- Since <code style="white-space: normal">sp_counted_base_impl<P, D></code> is derived from
- <code style="white-space: normal">sp_counted_base</code>, the following is needed:
- <pre><code>
- template<class Archive, class P, class D>
- inline void serialize(
- Archive & ar,
- boost::detail::sp_counted_base_impl<P, D> & t,
- const unsigned int file_version,
- int
- ){
- ar & boost::serialization::base_object<
- boost::detail::sp_counted_base
- >(*this);
- }
- </code></pre>
- which will in turn require serialization of its base class:
- <pre><code>
- inline void serialize(
- Archive & ar,
- boost::detail::sp_counted & t,
- const unsigned int file_version,
- int
- ){
- }
- </code></pre>
- It would seem we're done, but running the test program,
- <a href="../example/demo_shared_ptr.cpp" target="demo_shared_ptr_cpp">
- demo_shared_ptr.cpp
- </a>,
- with this code produces the following output.
- <pre><code>
- a = 0x003017A0 use count = 2
- a1 = 0x003017A0 use count = 2
- unique element count = 1
- a = 0x00000000 use count = 0
- a1 = 0x00000000 use count = 0
- unique element count = 0
- a = 0x00303060 use count = 1
- a1 = 0x00303060 use count = 1
- unique element count = 1
- </code></pre>
- This indicates that we're not quite done. Due to default object
- tracking, <code style="white-space: normal">sp_counted_base_impl<P, D></code> is only
- created once regardless of how many shared pointers point to the
- same object. Of course, it has to be this way. The reference
- count starts at 1 and is never incrememented. Code must be added
- to the serialization functions to maintain the proper reference
- count.
- <p>
- The process of serialization of an empty base class -
- <code style="white-space: normal">sp_counted_base</code> - seems like additional overhead.
- Examination of code in
- <a href="../../../boost/serialization/base_object.hpp" target="base_object_hpp">
- base_object.hpp
- </a>
- reveals that <code style="white-space: normal">base_object.hpp</code> provides two functions:
- <ul>
- <li>invokes serialization of the base class data
- <li>as a side effect, "registers" the fact base/derived relationship
- so that conversions of pointers between base and derived classes can be
- made at runtime.
- </ul>
- In this case we need only the latter function so we can replace the
- base object serialization with:
- <pre><code>
- // register the relationship between each derived class
- // its polymorphic base
- void_cast_register<
- boost::detail::sp_counted_base_impl<P, D>
- boost::detail::sp_counted_base,
- >();
- </code></pre>
- and we don't have to include a trival serializer for <code style="white-space: normal">sp_counted_base</code>.
- <p>
- Finally we need to specify name-value pair wrappers if we want to be able
- to use this serialization with XML archives.
- <p>
- Actually, even this is really just a start. Among the issues not addressed in
- this implementation are:
- <ul>
- <li><code style="white-space: normal">weak_ptr</code> is not addressed. I haven't even looked into this.
- <li>Other smart pointers that might interact with <code style="white-space: normal">shared_ptr</code>
- haven't been addressed at all. To be confident that the implementation is
- complete and correct, all these should be addressed as well.
- <li>Exception handling hasn't been exhaustively considered.
- <li>Other issues yet to be discovered.
- </ul>
- One thing that has been considered is export of shared_ptr. The header which
- declares shared pointer serialization includes some special macros for exporting
- shared pointers:
- <code><pre>
- BOOST_SHARED_POINTER_EXPORT(T)
- BOOST_SHARED_POINTER_EXPORT_GUID(T, K)
- </pre></code>
- These are specialized versions of the macros used for exporting classes serialized through raw pointers.
- <p>
- Clear, complete, correct and exception safe serialization of smart pointers is going to
- be a challenge. I hope that this implementation provides a useful
- starting point for such an effort.
- <hr>
- <p><i>© Copyright <a href="http://www.rrsd.com">Robert Ramey</a> 2002-2004.
- 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>
|