tested with statically loaded dlls

[SVN r41298]
This commit is contained in:
Robert Ramey
2007-11-22 08:17:38 +00:00
parent 4845240fb0
commit 89bba6d009
5 changed files with 213 additions and 155 deletions

View File

@@ -148,6 +148,7 @@ function initialize() {
<dt><img style="display:none" src="plus.gif" id="derivedpointers"><a target="detail" href="serialization.html#derivedpointers">Pointers to Objects of Derived Classes</a>
<dd><div id="derivedpointers_detail"><dl class="page-index">
<dt><img style="display:none" src="dot.gif"><a target="detail" href="serialization.html#registration">Registration</a>
<dt><img style="display:none" src="dot.gif"><a target="detail" href="serialization.html#export">Export</a>
<dt><img style="display:none" src="dot.gif"><a target="detail" href="serialization.html#instantiation">Instantiation</a>
<dt><img style="display:none" src="dot.gif"><a target="detail" href="serialization.html#selectivetracking">Selective Tracking</a>
<dt><img style="display:none" src="dot.gif"><a target="detail" href="serialization.html#runtimecasting">Runtime Casting</a>
@@ -262,8 +263,8 @@ function initialize() {
<dt><img style="display:none" src="dot.gif"><a target="detail" href="pimpl.html">PIMPL</a>
<dt><img style="display:none" src="dot.gif"><a target="detail" href="derivation.html">Derivation from an Existing Archive Class</a>
</dl></div></dd>
<dt><img style="display:none" src="plus.gif" id="miscellaneous">Miscellaneous
<dd><div id="miscellaneous_detail"><dl class="page-index">
<dt><img style="display:none" src="plus.gif" id="otherclasses">Other Classes
<dd><div id="otherclasses_detail"><dl class="page-index">
<dt><img style="display:none" src="plus.gif" id="extended_type_info"><a target="detail" href="extended_type_info.html"><code>extended_type_info</code></a>
<dd><div id="extended_type_info_detail"><dl class="page-index">
<dt><img style="display:none" src="dot.gif"><a target="detail" href="extended_type_info.html#motivation">Motivation</a>
@@ -278,6 +279,15 @@ function initialize() {
<dt><img style="display:none" src="dot.gif"><a target="detail" href="dataflow.html">Dataflow Iterators</a>
<dt><img style="display:none" src="dot.gif"><a target="detail" href="smart_cast.html"><code>smart_cast</code></a>
<dt><img style="display:none" src="dot.gif"><a target="detail" href="static_warning.html"><code>BOOST_STATIC_WARNING</code></a>
<dt><img style="display:none" src="plus.gif" id="singleton"><a target="detail" href="singleton.html"><code>singleton</code></a>
<dd><div id="singleton_detail"><dl class="page-index">
<dt><img style="display:none" src="dot.gif"><a target="detail" href="singleton.html#motivation">Motivation</a>
<dt><img style="display:none" src="dot.gif"><a target="detail" href="singleton.html#features">Features</a>
<dt><img style="display:none" src="dot.gif"><a target="detail" href="singleton.html#classinterface">Class Interface</a>
<dt><img style="display:none" src="dot.gif"><a target="detail" href="singleton.html#requirements">Requirements</a>
<dt><img style="display:none" src="dot.gif"><a target="detail" href="singleton.html#examples">Examples</a>
<dt><img style="display:none" src="dot.gif"><a target="detail" href="singleton.html#multithreading">Multi-Threading</a>
</dl></div></dd>
</dl></div></dd>
<!--
<dt><img style="display:none" src="dot.gif"><a target="detail" href="configuration.html">Configuration Information</a></dt>

View File

@@ -61,11 +61,6 @@ the following functions
different applications. In fact, including different headers in different
name spaces is an accepted method used to avoid name space conflicts.
Thus the namespace::class_name can't be used as a key.
<li>
We may want the ability to serialize objects through a base class even though
they have no <code style="white-space: normal">virtual</code> function. That
is, objects of classes which are not polymorphic in the strict C++ sense. This
is not supported by the standard system.
<li>
There exists the possibility that different classes use different type id
mechanism. The class header might include this information. If we want to
@@ -80,8 +75,8 @@ following features:
<ul>
<li>
Builds a set of <a target="extended_type_info.hpp" href = "../../../boost/serialization/extended_type_info.hpp">
<code style="white-space: normal">extended_type_info</a></code> records - one for each type known
to the program.
<code style="white-space: normal">extended_type_info</a></code> records - one for each type
serialized.
<li>
permits association of an arbitrary string key with a type. Often this key would
be the class name - but it doesn't have to be. This key is referred to as
@@ -104,40 +99,52 @@ in order to construct types serialized through a base class pointer.
namespace boost {
namespace serialization {
class BOOST_SERIALIZATION_DECL extended_type_info :
private boost::noncopyable
class extended_type_info
{
protected:
// this class can't be used as is. It's just the
// common functionality for all type_info replacement
// systems. Hence, make these protected
extended_type_info();
~extended_type_info();
const char * m_key;
extended_type_info(const char * type_info_key);
extended_type_info(const unsigned int type_info_key);
~extended_type_info();
public:
void key_register(const char *key);
const char * get_key() const;
const char * get_key() const {
return m_key;
}
bool operator<(const extended_type_info &rhs) const;
bool operator==(const extended_type_info &rhs) const;
bool operator!=(const extended_type_info &rhs) const {
return !(operator==(rhs));
}
static const extended_type_info * find(const char *key);
};
bool operator<(const extended_type_info &rhs) const;
bool operator==(const extended_type_info &rhs) const;
} // namespace serialization
} // namespace boost
</code></pre>
There must be one and only one <code style="white-space: normal"><a target="extended_type_info.hpp" href = "../../../boost/serialization/extended_type_info.hpp">extended_type_info</a></code>
instance created for each type. For this reason, this class is marked is derived from
<code style="white-space: normal">boost::noncopyable</code>.
<p>
Generally, there will be one and only one
<code style="white-space: normal"><a target="extended_type_info.hpp" href = "../../../boost/serialization/extended_type_info.hpp">extended_type_info</a></code>
instance created for each type. However, this is enforced only at the executable
module level. That is, if a program includes some shared libraries or DLLS,
there may be more than one instance of this class correponding to a particular type.
For this reason the comparison functions below can't just compare the addresses of
this instance but rather must be programmed to compare the the actual information
the instances contain.
<dl>
<dt><h4><pre><code>
extended_type_info(const char * type_info_key);</code></pre></h4></dt>
extended_type_info(unsigned int type_info_key);
</code></pre></h4></dt>
<dd>
This constructor should be called by all derived classes.
The argument should be the particular implementation. For
this default implementation base on typeid(), this is the
value 1. Each system must have its own integer. This value
is used to permit the inter-operability of different typeinfo
systems.
</dd>
<dt><h4><pre><code>
@@ -153,6 +160,8 @@ For this purpose, it must be the same in all program instances which
refer to the same type.
<p>
It may sometimes be referred to as a GUID - a <b>G</b>lobal <b>U</b>nique <b>ID</b>entifier.
</dd>
<dt><h4><pre><code>
const char *get_key() const;
</code></pre></h4></dt>
@@ -162,35 +171,25 @@ instance. If no key has been associated with the instance, then a NULL is retur
</dd>
<dt><h4><pre><code>
// in order
bool operator==(
const extended_type_info & lhs,
const extended_type_info & rhs
);
bool operator<(
const extended_type_info & lhs,
const extended_type_info & rhs
);
} // namespace serialization
} // namespace boost
bool operator<(const extended_type_info & rhs) const;
bool operator==(const extended_type_info & rhs) const;
bool operator!=(const extended_type_info & rhs) const;
</code></pre></h4></dt>
<dd>
These non-member functions are used to compare two
These functions are used to compare two
<a target="extended_type_info.hpp" href = "../../../boost/serialization/extended_type_info.hpp">
<code style="white-space: normal">
extended_type_info
</code>
</a>
objects. They a strict total ordering on all instances of this class and
are used to implement the following.
objects. They a strict total ordering on all instances of this class.
<dt><h4><pre><code>
static const extended_type_info * find(const char *key);
</code></pre></h4></dt>
<dd>
Given a character string key or <strong>GUID</strong>, return the address of the
unique corresponding <code style="white-space: normal"><a target="extended_type_info.hpp" href = "../../../boost/serialization/extended_type_info.hpp">extended_type_info</a></code>
Given a character string key or <strong>GUID</strong>, return the address of a
corresponding <code style="white-space: normal"><a target="extended_type_info.hpp" href = "../../../boost/serialization/extended_type_info.hpp">extended_type_info</a></code>
object.
</dl>
@@ -224,8 +223,8 @@ this just amounts to returning the address of this static object.
<dt><h4><code style="white-space: normal"><pre>
template&lt;class ETI&gt;
static const extended_type_info *
ETI::get_derived_extended_type_info(const T & t);
const extended_type_info *
ETI::get_derived_extended_type_info(const T & t) const;
</pre></code></h4></dt>
<dd>
Return a pointer to the
@@ -235,7 +234,14 @@ the "true type" of the type T. The "true type" is the lowest type in the
hierarchy of classes. The type T can always be cast to the "true type" with
a static cast. Implemention of this function will vary among type id systems
and sometimes will make presumptions about the type T than can be identified
with a particular <code style="white-space: normal">extended_type_info implementation</code>.
with a particular <code style="white-space: normal">extended_type_info</code> implementation.
</dd>
<dt><h4><code style="white-space: normal"><pre>
bool ETI::less_than(const extended_type_info &rhs) const;
</pre></code></h4></dt>
<dd>
Compare this instance to another one.
</dd>
</dl>
@@ -266,7 +272,9 @@ as described above.
The test program <code style="white-space: normal"><a target="test_no_rtti" href="../test/test_no_rtti.cpp">test_no_rtti</a></code>
implements this function in terms of the <code style="white-space: normal"><a target="extended_type_info_no_rtti.hpp" href="../../../boost/serialization/extended_type_info_no_rtti.hpp">
extended_type_info</a></code> API above to return the export key associated with the class.
This requires that non-abstract types be exported.
This requires that non-abstract types be exported. It also demostrates the
inter-operability with between two different implementations of
<code style="white-space: normal">extended_type_info</code>.
<hr>
<p><i>&copy; Copyright <a href="http://www.rrsd.com">Robert Ramey</a> 2005.

View File

@@ -54,6 +54,7 @@ http://www.boost.org/LICENSE_1_0.txt)
<dt><a href="#derivedpointers">Pointers to Objects of Derived Classes</a>
<dl class="page-index">
<dt><a href="#registration">Registration</a>
<dt><a href="#export">Export</a>
<dt><a href="#instantiation">Instantiation</a>
<dt><a href="#selectivetracking">Selective Tracking</a>
<dt><a href="#runtimecasting">Runtime Casting</a>
@@ -676,8 +677,9 @@ main(){
Note that if the serialization function is split between save and load, both
functions must include the registration. This is required to keep the save
and corresponding load in syncronization.
<p>
This will work but may be inconvenient. We don't always know which derived
<h4><a name="export">Export</a></h4>
The above will work but may be inconvenient. We don't always know which derived
classes we are going to serialize when we write the code to serialize through
a base class pointer. Every time a new derived class is written we have to
go back to all the places where the base class is serialized and update the

View File

@@ -27,7 +27,6 @@ http://www.boost.org/LICENSE_1_0.txt)
<hr>
<dl class="page-index">
<dt><a href="#objecttracking">Object Tracking</a>
<dt><a href="#export">Exporting Class Serialization</a>
<dt><a href="#classinfo">Class Information</a>
<dt><a href="#portability">Archive Portability</a>
<dl class="page-index">
@@ -36,6 +35,7 @@ http://www.boost.org/LICENSE_1_0.txt)
</dl>
<dt><a href="#binary_archives">Binary Archives</a>
<dt><a href="#xml_archives">XML Archives</a>
<dt><a href="#export">Exporting Class Serialization</a>
<dt><a href="#dlls">DLLS - Serialization and Runtime Linking</a>
<dt><a href="#multi_threading">Multi-Threading</a>
<dt><a href="#optimizations">Optimizations</a>
@@ -153,63 +153,6 @@ redundant save/load operations.
BOOST_CLASS_TRACKING(my_virtual_base_class, boost::serialization::track_always)
</code></pre>
<h3><a name="export">Exporting Class Serialization</a></h3>
<a target="detail" href="traits.html#export">Elsewhere</a> in this manual, we have described
<code style="white-space: normal">BOOST_CLASS_EXPORT</code>. This is used to make the serialization library aware
that code should be instantiated for serialization of a given class even though the
class hasn't been otherwise referred to by the program. This functionality
is necessary to implement serialization of pointers through a virtual base
class pointer. That is, a polymorphic pointer.
<p>
This macro specifies a "<b>G</b>lobally <b>U</b>nique <b>ID</b>entifier".
This is an string which identifies the class to be created when data is loaded.
Generally a text representation of the class name is sufficient for this purpose,
but in certain cases it maybe necessary to specify a different string by using
<code style="white-space: normal">BOOST_CLASS_EXPORT_GUID</code>
rather than a simple
<code style="white-space: normal">BOOST_CLASS_EXPORT</code>.
<p>
<code style="white-space: normal">BOOST_CLASS_EXPORT</code> would usually
be specified in the same header file as the class declaration to which it
corresponds. That is, <code style="white-space: normal">BOOST_CLASS_EXPORT(T)</code>
is a "trait" of the class T. So a program using this class will look
something like:
<pre><code>
#include &lt;boost/archive/xml_oarchive.hpp&gt;
.... // any other archive classes
#include "my_class.hpp" // which contains BOOST_CLASS_EXPORT(my_class)
</code></pre>
These headers can be in any order. (In boost versions 1.34
and earlier, the archive headers had to go before any headers which
contain <code style="white-space: normal">BOOST_CLASS_EXPORT</code>.)
Any code required to serialize types specified
by <code style="white-space: normal">BOOST_CLASS_EXPORT</code> will be
instantiated for each archive whose header is included. (note that the code
is instantiated regardless of whether or not it is actually invoked.)
If no archive headers are included - no code should be instantiated.
This will permit <code style="white-space: normal">BOOST_CLASS_EXPORT</code>
to be a permanent part of the <code style="white-space: normal">my_class.hpp</code> .
<p>
Strictly speaking, export should not be necessary if all pointer serialization
occurs through the most derived class. However, in order to detect
what would be catastophic error, the library traps ALL serializations through
a pointer to a polymorphic which are not exported or otherwise registered.
So, in practice, be prepared to register or export all classes with one
or more virtual functions which are serialized through a pointer.
<p>
Note that the implementation of this functionality depends upon vendor
specific extensions to the C++ language. So, there is no guarenteed portability
of programs which use this facility. However, all C++ compilers which
are tested with boost provide the required extensions. The library
includes the extra declarations required by each of these compilers.
It's reasonable to expect that future C++ compilers will support
these extensions or something equivalent.
<h3><a name="classinfo">Class Information</a></h3>
By default, for each class serialized, class information is written to the archive.
This information includes version number, implementation level and tracking
@@ -294,7 +237,7 @@ struct my_wrapper {
class my_class {
wchar_t a;
short unsigned b;
template<&lt;class Archive&gt;
template&lt;class Archive&gt;
Archive & serialize(Archive & ar, unsigned int version){
ar & my_wrapper(a);
ar & my_wrapper(b);
@@ -353,13 +296,105 @@ just the value portion of the data is serialized. The name portion is discarded
So by always using <a target="detail" href="wrappers.html#nvp">name-value pairs</a>, it will
be guarenteed that all data can be serialized to all archive classes with maximum efficiency.
<h3><a name="export">Exporting Class Serialization</a></h3>
<a target="detail" href="traits.html#export">Elsewhere</a> in this manual, we have described
<code style="white-space: normal">BOOST_CLASS_EXPORT</code>.
Export implies two things:
<ul>
<li>Instantiates code which is not otherwise referred to.
<li>Associates an external identifier with the class to be serialized.
The fact that the class isn't explicitly referred to implies this
requirement.
</ul>
In C++, usage of code not explicitly referred to is implemented via
virtual functions. Hence, the need for export is implied by the
usage of a derived class that is manipulated via a pointer or
reference to it's base class.
<p>
<code style="white-space: normal">BOOST_CLASS_EXPORT</code> in the same
source module that includes any of the archive class headers will
instantiate code required to serialize polymorphic pointers of
the indicated type to the all those archive classes. If no
archive class headers are included, then no code will be instantiated.
<p>
Note that the implemenation of this functionality requires
that the <code style="white-space: normal">BOOST_CLASS_EXPORT</code>
macro appear <b>after</b> and the inclusion of any archive
class headers for which code is to be instantiated.
So, code that uses <code style="white-space: normal">BOOST_CLASS_EXPORT</code>
will look like the following:
<pre><code>
#include &lt;boost/archive/text_oarchive.hpp&gt;
#include &lt;boost/archive/text_oarchive.hpp&gt;
... // other archives
#include "a.hpp" // header declaration for class a
BOOST_CLASS_EXPORT(a)
... // other class headers and exports
</code></pre>
This will be true regardless of whether the is part
of a stand alone executable, a static library or
a dyanmic or shared library.
<p>
Note that including
<code style="white-space: normal">BOOST_CLASS_EXPORT</code>
in the "a.hpp" header itself as one would do with
other serialization traits will make it difficult
or impossible to follow the rule above regarding
inclusion of archive headers before
<code style="white-space: normal">BOOST_CLASS_EXPORT</code>
is invoked. This is different than other serialization
traits which would normally be included in same file
as the class declaration.
<p>
This system has certain implications for placing code in static or shared
libraries. Placing <code style="white-space: normal">BOOST_CLASS_EXPORT</code>
in library code will have no effect unless archive class headers are
also included. So when building a library, one should include all headers
for all the archive classes which he anticipates using. Alternatively,
one can include headers for just the
<a href="archive_reference.html#polymorphic">Polymoprhic Archives</a>.
Also, when making shared libraries, there is currently a restriction
that only one such library can use <code style="white-space: normal">BOOST_CLASS_EXPORT</code>
for any given type. All this will most likely make it inconvenient
to include <code style="white-space: normal">BOOST_CLASS_EXPORT</code>
as part of the header of the class to be serialized. In this case
it would probably be best to include it in source module which
implements the class.
<p>
Strictly speaking, export should not be necessary if all pointer serialization
occurs through the most derived class. However, in order to detect
what would be catastophic error, the library traps ALL serializations through
a pointer to a polymorphic which are not exported or otherwise registered.
So, in practice, be prepared to register or export all classes with one
or more virtual functions which are serialized through a pointer.
<p>
Note that the implementation of this functionality depends upon vendor
specific extensions to the C++ language. So, there is no guarenteed portability
of programs which use this facility. However, all C++ compilers which
are tested with boost provide the required extensions. The library
includes the extra declarations required by each of these compilers.
It's reasonable to expect that future C++ compilers will support
these extensions or something equivalent.
<h3><a name="dlls">DLLS - Serialization and Runtime Linking</a></h3>
Serialization code can be placed in libraries to be linked at runtime. That is,
code can be placed in DLLS(Windows) or Shared Libraries(*nix).
Along with the "export" facility, this
permits a program to written without knowledge of the actual types to be serialized.
This package doesn't include an example of this technique - but coding would be
very similar to the example
code can be placed in DLLS(Windows) Shared Libraries(*nix), or static libraries
as well as the main executable. As long as
<a target="detail" href="serialization.html#export">
<code style="white-space: normal">BOOST_CLASS_EXPORT</code>
</a>
is not used, The serialization library imposes no special requirements
that need be taken into account when distributing code among various modules.
<p>
For static libraries, this is illustrated by
<a href = "../example/demo_pimpl.cpp" target="demo_pimpl">
<code style="white-space: normal">demo_pimpl.cpp</code>
</a>,
@@ -370,52 +405,55 @@ and
<a href = "../example/demo_pimpl_A.hpp" target="demo_pimpl">
<code style="white-space: normal">demo_pimpl_A.hpp</code>
</a>
where implementation of serializaton is completely separate
from the main program.
where implementation of serializaton is in a static library
completely separate from the main program.
<p>
For runtime linked libraries this is illustrated by one of the tests:
<a href = "../test/test_dll_simple.cpp" target="test_dll_simple">
<code style="white-space: normal">test_dll_simple</code>
</a>,
and
<a href = "../test/dll_A.cpp" target="dll_A">
<code style="white-space: normal">dll_A.cpp</code>
</a>
where implementation of serializaton is also completely separate
from the main program but the code is loaded at runtime. In this
example, this code is loaded automatically when the program which
uses it starts up, but it could just as well be loaded and unloaded
with an OS dependent API call.
<h3><a name="multi_threading">Multi-Threading</a></h3>
The nature of serialization would conflict with multiple thread concurrently
writing/reading from/to a single open archive. Since each archive is
independent from ever other one, there should be no problem
in having multiple open archives from one or more threads.
The fundamental purpose of serialization would conflict with multiple
thread concurrently writing/reading from/to a single open archive instance.
The library implementation presumes that the application avoids such an situtation.
<p>
Well, not quite.
However, Writing/Reading different archives simultaneously
in different tasks is permitted as each archive instance is (almost)
completely independent from any other archive instance. The only shared
information are some type tables which have been implemented using a
lock-free thread-safe
<a target="detail" href="singleton.html">
<code style="white-space: normal">singleton</code>
</a>
described elsewhere in this documentation.
<p>
There are a couple of global data structures for holding
information of serializable types. These structures are
used to dispatch to correct code to handle each pair
of serializable types and archive types. Since this
information is shared among all archives, there is
potential for problems. This has been addressed
carefully implementing the library so that these
structures are all initialized before
<code style="white-space: normal">main(...)</code>
is called. From then on they are never altered. So
there SHOULD be no problem having mulitple archives
open simultaneously - be it from the same or different
threads.
<p>
Well, almost.
<p>
With dynamically loaded code - DLLS or Shared Libraries,
these global data structures can be altered when a library
is loaded or unloaded. That is, in this case, these
globa data structures can be altered after
<code style="white-space: normal">main(...)</code>
is called. So if a thread is dynamically loading/unloading
modules which contain serialization code while an
archive is open there could be problems. Also, if
such loading/unloading is happening concurrently
in different threads, there could also be problems.
<p>
It might not be easy to control this. Is possible that
some systems may not actually load modules until they
are actually needed. So even though we think that
there is not dynamic loading/unloading of such code
it could be occurring as "help" to manage resources.
On such systems, access to archive code would have
to be syncronized with some multi-threading construct
in order to be functional.
This singleton implemenation guarentees that all of this shared
information is initialized when the code module which contains
them is loaded. The serialization library takes care to
ensure that these data structures are not subsequently
modified. The only time there could be a problem would
be if code is loaded/unloaded while another task is
serializing data. This could only occur for types whose
serialization is implemented in a dynamically loaded/unload DLL
or shared library. So if the following is avoided:
<ul>
<li>Accessing the same archive instance from different tasks.
<li>Loading/Unloading DLLS or shared libraries while any archive
instances are open.
</ul>
The library should be thread safe.
<h3><a name="optimizations">Optimizations</a></h3>
In performance critical applications that serialize large sets of contiguous data of homogeneous

View File

@@ -44,8 +44,8 @@ They are declared in the namespace
template&lt;class Derived, class Base&gt;
const void_cast_detail::void_caster &
void_cast_register(
const Derived * derived = NULL,
const Base * base = NULL
Derived const * derived = NULL,
Base * const base = NULL
)
</code></pre></h4></dt>
<dd>