Initial HTML commit

[SVN r7640]
This commit is contained in:
Beman Dawes
2000-07-27 14:27:00 +00:00
parent ed7e13da9f
commit d3347b6d08
7 changed files with 1319 additions and 0 deletions

37
index.htm Normal file
View File

@ -0,0 +1,37 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Boost Smart Pointer Library</title>
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<table border="1" bgcolor="#007F7F" cellpadding="2">
<tr>
<td bgcolor="#FFFFFF"><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" WIDTH="277" HEIGHT="86"></td>
<td><a href="../../index.htm"><font face="Arial" color="#FFFFFF"><big>Home </big></font></a></td>
<td><a href="../../libraries.htm"><font face="Arial" color="#FFFFFF"><big>Libraries </big></font></a></td>
<td><a href="../../people.htm"><font face="Arial" color="#FFFFFF"><big>People </big></font></a></td>
<td><a href="../../more/faq.htm"><font face="Arial" color="#FFFFFF"><big>FAQ </big></font></a></td>
<td><a href="../../more/index.htm"><font face="Arial" color="#FFFFFF"><big>More </big></font></a></td>
</tr>
</table>
<h1>Smart pointer library</h1>
<p>The header smart_ptr.h provides four smart pointer classes.&nbsp; Smart pointers ease
the management of memory dynamically allocated with C++ <strong>new</strong> expressions.
<ul>
<li><a href="smart_ptr.htm">Documentation</a> (HTML).</li>
<li>Header <a href="../../boost/smart_ptr.hpp">smart_ptr.hpp</a></li>
<li>Test program <a href="smart_ptr_test.cpp">smart_ptr_test.cpp</a>.</li>
<li>Download <a href="../../boost_all.zip"> all of Boost</a> (ZIP format).</li>
<li>Submitted by <a href="../../people/greg_colvin.htm">Greg Colvin</a> and <a href="../../people/beman_dawes.html">Beman Dawes</a>.</li>
</ul>
<p>Revised July 23, 1999</p>
</body>
</html>

90
scoped_array.htm Normal file
View File

@ -0,0 +1,90 @@
<html>
<head>
<title>scoped_array</title>
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Class
<a name="scoped_array">scoped_array</a></h1>
<p>Class <strong>scoped_array</strong> stores a pointer to a dynamically
allocated array. (Dynamically allocated arrays are allocated with the C++ <tt>new[]</tt>
expression.)&nbsp;&nbsp; The array pointed to is guaranteed to be deleted,
either on destruction of the <strong>scoped_array</strong>, or via an explicit <strong>scoped_array::reset()</strong>.</p>
<p>Class<strong> scoped_array</strong> is a simple solution for simple
needs.&nbsp; It cannot be used in C++ Standard Library containers.&nbsp; See <a href="shared_array.htm"><strong>shared_array</strong></a>
if <strong>scoped_array</strong> does not meet your needs.</p>
<p>Class<strong> scoped_array</strong> cannot correctly hold a pointer to a
single object.&nbsp; See <a href="scoped_ptr.htm"><strong>scoped_ptr</strong></a>
for that usage.</p>
<p>Because <strong>scoped_array</strong> is so simple, in its usual
implementation every operation is as fast as a built-in array pointer and has no
more space overhead that a built-in array pointer.</p>
<p>A heavier duty alternative to a <strong>scoped_array</strong> is a <strong>scoped_ptr</strong>
to a C++ Standard Library <strong>vector</strong>.</p>
<p>The class is a template parameterized on <tt>T</tt>, the type of the object
pointed to.&nbsp;&nbsp; <tt>T</tt> must meet the smart pointer <a href="smart_ptr.htm#Common requirements">common
requirements</a>.</p>
<h2>Class scoped_array Synopsis</h2>
<pre>#include &lt;boost/smart_ptr.hpp&gt;
namespace boost {
template&lt;typename T&gt; class scoped_array : <a href="../utility/utility.htm#noncopyable">noncopyable</a> {
public:
typedef T <a href="#scoped_array_element_type">element_type</a>;
explicit <a href="#scoped_array_ctor">scoped_array</a>( T* p=0 ); // never throws
<strong> </strong><a href="#scoped_array_~scoped_array">~scoped_array</a>();
void <a href="#scoped_array_reset">reset</a>( T* p=0 );
T&amp; <a href="#scoped_array_operator[]">operator[]</a>(std::size_t i) const; // never throws
T* <a href="#scoped_array_get">get</a>() const; // never throws
};
}</pre>
<h2>Class scoped_array Members</h2>
<h3>scoped_array <a name="scoped_array_element_type">element_type</a></h3>
<pre>typedef T element_type;</pre>
<p>Provides the type of the stored pointer.</p>
<h3><a name="scoped_array_ctor">scoped_array constructors</a></h3>
<pre>explicit scoped_array( T* p=0 ); // never throws</pre>
<p>Constructs a <tt>scoped_array</tt>, storing a copy of <tt>p</tt>, which must
have been allocated via a C++ <tt>new</tt>[] expression or be 0.</p>
<h3><a name="scoped_array_~scoped_array">scoped_array destructor</a></h3>
<pre>~scoped_array();</pre>
<p>Deletes the array pointed to by the stored pointer.&nbsp; Note that in C++ <tt>delete</tt>[]
on a pointer with a value of 0 is harmless.</p>
<p>Does not throw exceptions.</p>
<h3>scoped_array <a name="scoped_array_reset">reset</a></h3>
<pre>void reset( T* p=0 )();</pre>
<p>If p is not equal to the stored pointer, deletes the array pointed to by the
stored pointer and then stores a copy of p, which must have been allocated via a
C++ <tt>new[]</tt> expression or be 0.</p>
<p>Does not throw exceptions.</p>
<h3>scoped_array <a name="scoped_array_operator[]">operator[]</a></h3>
<p><tt>T&amp; operator[](std::size_t i) const; // never throws</tt></p>
<p>Returns a reference to element <tt>i</tt> of the array pointed to by the
stored pointer.</p>
<p>Behavior is undefined (and almost certainly undesirable) if <tt>get()==0</tt>,
or if <tt>i</tt> is less than 0 or is greater or equal to the number of elements
in the array.</p>
<h3>scoped_array <a name="scoped_array_get">get</a></h3>
<pre>T* get() const; // never throws</pre>
<p>Returns the stored pointer.</p>
<h2>Class <a name="shared_array_example">scoped_array example</a></h2>
<p>[To be supplied. In the meantime, see <a href="smart_ptr_test.cpp">smart_ptr_test.cpp</a>.]</p>
<hr>
<p>Revised&nbsp; December 8, 1999</p>
<p><EFBFBD> Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use,
modify, sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &quot;as is&quot;
without express or implied warranty, and with no claim as to its suitability for
any purpose.</p>
</body>
</html>

128
scoped_ptr.htm Normal file
View File

@ -0,0 +1,128 @@
<html>
<head>
<title>scoped_ptr</title>
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Class
<a name="scoped_ptr">scoped_ptr</a></h1>
<p>Class <strong>scoped_ptr</strong> stores a pointer to a dynamically allocated
object. (Dynamically allocated objects are allocated with the C++ <tt>new</tt>
expression.)&nbsp;&nbsp; The object pointed to is guaranteed to be deleted,
either on destruction of the <strong>scoped_ptr</strong>, or via an explicit <strong>scoped_ptr::reset()</strong>.&nbsp;
See <a href="#scoped_ptr_example">example</a>.</p>
<p>Class<strong> scoped_ptr</strong> is a simple solution for simple
needs.&nbsp; It cannot be used in C++ Standard Library containers.&nbsp; See <a href="shared_ptr.htm"><strong>shared_ptr</strong></a>
or std::auto_ptr if <strong>scoped_ptr</strong> does not meet your needs.</p>
<p>Class<strong> scoped_ptr</strong> cannot correctly hold a pointer to a
dynamically allocated array.&nbsp; See <a href="scoped_array.htm"><strong>scoped_array</strong></a>
for that usage.</p>
<p>Because <strong>scoped_ptr</strong> is so simple, in its usual implementation
every operation is as fast as a built-in pointer and has no more space overhead
that a built-in pointer.</p>
<p>The class is a template parameterized on <tt>T</tt>, the type of the object
pointed to.&nbsp;&nbsp; <tt>T</tt> must meet the smart pointer <a href="smart_ptr.htm#Common requirements">common
requirements</a>.</p>
<h2>Class scoped_ptr Synopsis</h2>
<pre>#include &lt;boost/smart_ptr.hpp&gt;
namespace boost {
template&lt;typename T&gt; class scoped_ptr : <a href="../utility/utility.htm#class noncopyable">noncopyable</a> {
public:
typedef T <a href="#scoped_ptr_element_type">element_type</a>;
explicit <a href="#scoped_ptr_ctor">scoped_ptr</a>( T* p=0 ); // never throws
<strong> </strong><a href="#scoped_ptr_~scoped_ptr">~scoped_ptr</a>();
void <a href="#scoped_ptr_reset">reset</a>( T* p=0 );
T&amp; <a href="#scoped_ptr_operator*">operator*</a>() const; // never throws
T* <a href="#scoped_ptr_operator-&gt;">operator-&gt;</a>() const; // never throws
T* <a href="#scoped_ptr_get">get</a>() const; // never throws
};
}</pre>
<h2>Class scoped_ptr Members</h2>
<h3>scoped_ptr <a name="scoped_ptr_element_type">element_type</a></h3>
<pre>typedef T element_type;</pre>
<p>Provides the type of the stored pointer.</p>
<h3><a name="scoped_ptr_ctor">scoped_ptr constructors</a></h3>
<pre>explicit scoped_ptr( T* p=0 ); // never throws</pre>
<p>Constructs a <tt>scoped_ptr</tt>, storing a copy of <tt>p</tt>, which must
have been allocated via a C++ <tt>new</tt> expression or be 0..</p>
<h3><a name="scoped_ptr_~scoped_ptr">scoped_ptr destructor</a></h3>
<pre>~scoped_ptr();</pre>
<p>Deletes the object pointed to by the stored pointer.&nbsp; Note that in C++, <tt>delete</tt>
on a pointer with a value of 0 is harmless.</p>
<p>Does not throw exceptions.</p>
<h3>scoped_ptr <a name="scoped_ptr_reset">reset</a></h3>
<pre>void reset( T* p=0 );</pre>
<p>If p is not equal to the stored pointer, deletes the object pointed to by the
stored pointer and then stores a copy of p, which must have been allocated via a
C++ <tt>new</tt> expression or be 0.</p>
<p>Does not throw exceptions.</p>
<h3>scoped_ptr <a name="scoped_ptr_operator*">operator*</a></h3>
<pre>T&amp; operator*() const; // never throws</pre>
<p>Returns a reference to the object pointed to by the stored pointer.</p>
<h3>scoped_ptr <a name="scoped_ptr_operator-&gt;">operator-&gt;</a> and <a name="scoped_ptr_get">get</a></h3>
<pre>T* operator-&gt;() const; // never throws
T* get() const; // never throws</pre>
<p>Both return the stored pointer.</p>
<h2>Class <a name="scoped_ptr_example">scoped_ptr example</a>s</h2>
<pre>#include &lt;iostream&gt;
#include &lt;boost/smart_ptr.h&gt;
struct Shoe { ~Shoe(){ std::cout &lt;&lt; &quot;Buckle my shoe&quot; &lt;&lt; std::endl; } };
class MyClass {
boost::scoped_ptr&lt;int&gt; ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; }
int add_one() { return ++*ptr; }
};
void main() {
boost::scoped_ptr&lt;Shoe&gt; x(new Shoe);
MyClass my_instance;
std::cout &lt;&lt; my_instance.add_one() &lt;&lt; std::endl;
std::cout &lt;&lt; my_instance.add_one() &lt;&lt; std::endl;
}</pre>
<p>The example program produces the beginning of a child's nursery rhyme as
output:</p>
<blockquote>
<pre>1
2
Buckle my shoe</pre>
</blockquote>
<h2>Handle/Body Idiom</h2>
<p>One common usage of <b>shared_pointer</b> is to implement a handle/body
structure which avoids exposing the body (implementation) in the header file:</p>
<pre>class handle
{
public: // simple forwarding functions to the body class
void f();
void g(int);
private:
friend class body; //incomplete class hides implementation
boost::scoped_ptr&lt;body&gt; imp;
};</pre>
<p>This code requires that <code>class body</code> have a trivial destructor to
avoid undefined behavior.&nbsp; This is because the definition of <code>class
body</code> is not visible at the time scoped_ptr&lt;&gt; deletes it. See ISO
5.3.5/5.&nbsp; Note that some compilers will issue a warning even though the
above code is well defined.</p>
<hr>
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B %Y" startspan -->24 July 2000<!--webbot bot="Timestamp" endspan i-checksum="18764" --></p>
<p><EFBFBD> Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use,
modify, sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &quot;as is&quot;
without express or implied warranty, and with no claim as to its suitability for
any purpose.</p>
</body>
</html>

180
shared_array.htm Normal file
View File

@ -0,0 +1,180 @@
<html>
<head>
<title>shared_array</title>
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Class
<a name="shared_array">shared_array</a></h1>
<p>Class <strong>shared_array</strong> stores a pointer to a dynamically
allocated array. (Dynamically allocated arrays are allocated with the C++ <tt>new[]</tt>
expression.)&nbsp;&nbsp; The array pointed to is guaranteed to be deleted,
either on destruction of the <strong>shared_array</strong>, on <strong>shared_array::operator=()</strong>,
or via an explicit <strong>shared_array::reset()</strong>.&nbsp; See <a href="#shared_array_example">example</a>.</p>
<p>Class<strong> shared_array</strong> meets the <strong>CopyConstuctible</strong>
and <strong>Assignable</strong> requirements of the C++ Standard Library, and so
can be used in C++ Standard Library containers.&nbsp; A specialization of std::
less&lt; &gt; for&nbsp; boost::shared_ptr&lt;Y&gt; is supplied so that&nbsp;<strong>
shared_array</strong> works by default for Standard Library's Associative
Container Compare template parameter.&nbsp; For compilers not supporting partial
specialization, the user must explicitly pass the less&lt;&gt; functor.</p>
<p>Class<strong> shared_array</strong> cannot correctly hold a pointer to a
single object.&nbsp; See <a href="shared_ptr.htm"><strong>shared_array</strong></a>
for that usage.</p>
<p>Class<strong> shared_array</strong> will not work correctly with cyclic data
structures. For example, if main() holds a shared_array pointing to array A,
which directly or indirectly holds a shared_array pointing back to array A, then
array A's use_count() will be 2, and destruction of the main() shared_array will
leave array A dangling with a use_count() of 1.</p>
<p>A heavier duty alternative to a <strong>shared_array</strong> is a <strong>shared_ptr</strong>
to a C++ Standard Library <strong>vector</strong>.</p>
<p>The class is a template parameterized on <tt>T</tt>, the type of the object
pointed to.&nbsp;&nbsp; <tt>T</tt> must meet the smart pointer <a href="smart_ptr.htm#Common requirements">Common
requirements</a>.</p>
<h2>Class shared_array Synopsis</h2>
<pre>#include &lt;boost/smart_ptr.hpp&gt;
namespace boost {
template&lt;typename T&gt; class shared_array {
public:
typedef T <a href="#shared_array_element_type">element_type</a>;
explicit <a href="#shared_array_ctor">shared_array</a>( T* p=0 );
<a href="#shared_array_ctor">shared_array</a>( const shared_array&amp; ); // never throws
<strong> </strong><a href="#shared_array_~shared_array">~shared_array</a>();
shared_array&amp; <a href="#shared_array_operator=">operator=</a>( const shared_array&amp; ); // never throws
void <a href="#shared_array_reset">reset</a>( T* p=0 );
T&amp; <a href="#shared_array_operator[]">operator[]</a>(std::size_t i) const; // never throws
T* <a href="#shared_array_get">get</a>() const; // never throws
long <a href="#shared_array_use_count">use_count</a>() const; // never throws
bool <a href="#shared_array_unique">unique</a>() const; // never throws
void <a href="#shared_array_swap">swap</a>( shared_array&lt;T&gt;&amp; other ) throw()
};
template&lt;typename T&gt;
inline bool operator==(const shared_array&lt;T&gt;&amp; a, const shared_array&lt;T&gt;&amp; b)
{ return a.get() == b.get(); }
template&lt;typename T&gt;
inline bool operator!=(const shared_array&lt;T&gt;&amp; a, const shared_array&lt;T&gt;&amp; b)
{ return a.get() != b.get(); }
}</pre>
<pre>namespace std {
template&lt;typename T&gt;
inline void swap(boost::shared_array&lt;T&gt;&amp; a, boost::shared_array&lt;T&gt;&amp; b)
{ a.swap(b); }
template&lt;typename T&gt;
struct less&lt; boost::shared_array&lt;T&gt; &gt;
: binary_function&lt;boost::shared_array&lt;T&gt;, boost::shared_array&lt;T&gt;, bool&gt;
{
bool operator()(const boost::shared_array&lt;T&gt;&amp; a,
const boost::shared_array&lt;T&gt;&amp; b) const
{ return less&lt;T*&gt;()(a.get(),b.get()); }
};
} // namespace std </pre>
<p>Specialization of std::swap uses the fast, non-throwing swap that's provided
as a member function instead of using the default algorithm which creates a
temporary and uses assignment.<br>
<br>
Specialization of std::less allows use of shared arrays as keys in&nbsp;C++
Standard Library associative collections.<br>
<br>
The std::less specializations use std::less&lt;T*&gt; to perform the
comparison.&nbsp; This insures that pointers are handled correctly, since the
standard mandates that relational operations on pointers are unspecified (5.9 [expr.rel]
paragraph 2) but std::less&lt;&gt; on pointers is well-defined (20.3.3 [lib.comparisons]
paragraph 8).<br>
<br>
It's still a controversial question whether supplying only std::less is better
than supplying a full range of comparison operators (&lt;, &gt;, &lt;=, &gt;=).</p>
<p>The current implementation does not supply the specializations if the macro
name BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION is defined.</p>
<h2>Class shared_array Members</h2>
<h3>shared_array <a name="shared_array_element_type">element_type</a></h3>
<pre>typedef T element_type;</pre>
<p>Provides the type of the stored pointer.</p>
<h3><a name="shared_array_ctor">shared_array constructors</a></h3>
<pre>explicit shared_array( T* p=0 );</pre>
<p>Constructs a <strong>shared_array</strong>, storing a copy of <tt>p</tt>,
which must have been allocated via a C++ <tt>new</tt>[] expression or be 0.
Afterwards, use_count() is 1 (even if p==0; see <a href="#shared_array_~shared_array">~shared_array</a>).</p>
<p>The only exception which may be thrown is <tt>std::bad_alloc</tt>.&nbsp; If
an exception is thrown,&nbsp; <tt>delete[] p</tt> is called.</p>
<pre>shared_array( const shared_array&amp; r); // never throws</pre>
<p>Constructs a <strong>shared_array</strong>, as if by storing a copy of the
pointer stored in <strong>r</strong>. Afterwards, <strong>use_count()</strong>
for all copies is 1 more than the initial <strong>r.use_count()</strong>.</p>
<h3><a name="shared_array_~shared_array">shared_array destructor</a></h3>
<pre>~shared_array();</pre>
<p>If <strong>use_count()</strong> == 1, deletes the array pointed to by the
stored pointer.&nbsp;Otherwise, <strong>use_count()</strong> for any remaining
copies is decremented by 1. Note that in C++ <tt>delete</tt>[] on a pointer with
a value of 0 is harmless.</p>
<p>Does not throw exceptions.</p>
<h3>shared_array <a name="shared_array_operator=">operator=</a></h3>
<pre>shared_array&amp; operator=( const shared_array&amp; r); // never throws</pre>
<p>First, if <strong>use_count()</strong> == 1, deletes the array pointed to by
the stored pointer.&nbsp;Otherwise, <strong>use_count()</strong> for any
remaining copies is decremented by 1. Note that in C++ <tt>delete</tt>[] on a
pointer with a value of 0 is harmless.</p>
<p>Then replaces the contents of <strong>this</strong>, as if by storing a copy
of the pointer stored in <strong>r</strong>. Afterwards, <strong>use_count()</strong>
for all copies is 1 more than the initial <strong>r.use_count()</strong>.&nbsp;</p>
<h3>shared_array <a name="shared_array_reset">reset</a></h3>
<pre>void reset( T* p=0 );</pre>
<p>First, if <strong>use_count()</strong> == 1, deletes the array pointed to by
the stored pointer.&nbsp;Otherwise, <strong>use_count()</strong> for any
remaining copies is decremented by 1. Note that in C++&nbsp; <tt>delete</tt>[]
on a pointer with a value of 0 is harmless.</p>
<p>Then replaces the contents of <strong>this</strong>, as if by storing a copy
of <strong>p</strong>, which must have been allocated via a C++ <tt>new</tt>[]
expression or be 0. Afterwards, <strong>use_count()</strong> is 1 (even if p==0;
see <a href="#shared_array_~shared_array">~shared_array</a>).</p>
<p>The only exception which may be thrown is <tt>std::bad_alloc</tt>.&nbsp; If
an exception is thrown,&nbsp; <tt>delete[] p</tt> is called.</p>
<h3>shared_array <a name="shared_array_operator[]">operator[]</a></h3>
<p><tt>T&amp; operator[](std::size_t i) const; // never throws</tt></p>
<p>Returns a reference to element <tt>i</tt> of the array pointed to by the
stored pointer.</p>
<p>Behavior is undefined (and almost certainly undesirable) if <tt>get()==0</tt>,
or if <tt>i</tt> is less than 0 or is greater or equal to the number of elements
in the array.</p>
<h3>shared_array <a name="shared_array_get">get</a></h3>
<pre>T* get() const; // never throws</pre>
<p>Returns the stored pointer.</p>
<h3>shared_array<a name="shared_array_use_count"> use_count</a></h3>
<p><tt>long use_count() const; // never throws</tt></p>
<p>Returns the number of <strong>shared_arrays</strong> sharing ownership of the
stored pointer.</p>
<h3>shared_array <a name="shared_array_unique">unique</a></h3>
<p><tt>bool unique() const; // never throws</tt></p>
<p>Returns <strong>use_count()</strong> == 1.</p>
<h3><a name="shared_array_swap">shared_array swap</a></h3>
<p><code>void swap( shared_array&lt;T&gt;&amp; other ) throw()</code></p>
<p>Swaps the two smart pointers, as if by std::swap.</p>
<h2>Class <a name="shared_array_example">shared_array example</a></h2>
<p>[To be supplied. In the meantime, see <a href="smart_ptr_test.cpp">smart_ptr_test.cpp</a>.]</p>
<hr>
<p>Revised December 8, 1999</p>
<p><EFBFBD> Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use,
modify, sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &quot;as is&quot;
without express or implied warranty, and with no claim as to its suitability for
any purpose.</p>
</body>
</html>

206
shared_ptr.htm Normal file
View File

@ -0,0 +1,206 @@
<html>
<head>
<title>shared_ptr</title>
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Class
<a name="shared_ptr">shared_ptr</a></h1>
<p>Class <strong>shared_ptr</strong> stores a pointer to a dynamically allocated
object. (Dynamically allocated objects are allocated with the C++ <tt>new</tt>
expression.)&nbsp;&nbsp; The object pointed to is guaranteed to be deleted when
the last <strong>shared_ptr</strong> pointing to it is deleted or reset.&nbsp;
See <a href="#shared_ptr_example">example</a>.</p>
<p>Class<strong> shared_ptr</strong> meets the <strong>CopyConstuctible</strong>
and <strong>Assignable</strong> requirements of the C++ Standard Library, and so
can be used in C++ Standard Library containers.&nbsp; A specialization of std::
less&lt; &gt; for&nbsp; boost::shared_ptr&lt;Y&gt; is supplied so that&nbsp;<strong>
shared_ptr</strong> works by default for Standard Library's Associative
Container Compare template parameter.&nbsp; For compilers not supporting partial
specialization, the user must explicitly pass the less&lt;&gt; functor.</p>
<p>Class<strong> shared_ptr</strong> cannot correctly hold a pointer to a
dynamically allocated array.&nbsp; See <a href="shared_array.htm"><strong>shared_array</strong></a>
for that usage.</p>
<p>Class<strong> shared_ptr</strong> will not work correctly with cyclic data
structures. For example, if main() holds a shared_ptr to object A, which
directly or indirectly holds a shared_ptr back to object A, then object A's
use_count() will be 2, and destruction of the main() shared_ptr will leave
object A dangling with a use_count() of 1.</p>
<p>The class is a template parameterized on <tt>T</tt>, the type of the object
pointed to.&nbsp;&nbsp; <tt>T</tt> must meet the smart pointer <a href="smart_ptr.htm#Common requirements">Common
requirements</a>.</p>
<h2>Class shared_ptr Synopsis</h2>
<pre>#include &lt;boost/smart_ptr.hpp&gt;
namespace boost {
template&lt;typename T&gt; class shared_ptr {
public:
typedef T <a href="#shared_ptr_element_type">element_type</a>;
explicit <a href="#shared_ptr_ctor">shared_ptr</a>( T* p=0 );
<strong> </strong><a href="#shared_ptr_~shared_ptr">~shared_ptr</a>();
<a href="#shared_ptr_ctor">shared_ptr</a>( const shared_ptr&amp; );
template&lt;typename Y&gt;
<a href="#shared_ptr_ctor">shared_ptr</a>(const shared_ptr&lt;Y&gt;&amp; r); // never throws
template&lt;typename Y&gt;
<a href="#shared_ptr_ctor">shared_ptr</a>(std::auto_ptr&lt;Y&gt;&amp; r);
shared_ptr&amp; <a href="#shared_ptr_operator=">operator=</a>( const shared_ptr&amp; ); // never throws
template&lt;typename Y&gt;
shared_ptr&amp; <a href="#shared_ptr_operator=">operator=</a>(const shared_ptr&lt;Y&gt;&amp; r); // never throws
template&lt;typename Y&gt;
shared_ptr&amp; <a href="#shared_ptr_operator=">operator=</a>(std::auto_ptr&lt;Y&gt;&amp; r);
void <a href="#shared_ptr_reset">reset</a>( T* p=0 );
T&amp; <a href="#shared_ptr_operator*">operator*</a>() const; // never throws
T* <a href="#shared_ptr_operator-&gt;">operator-&gt;</a>() const; // never throws
T* <a href="#shared_ptr_get">get</a>() const; // never throws
long <a href="#shared_ptr_use_count">use_count</a>() const; // never throws
bool <a href="#shared_ptr_unique">unique</a>() const; // never throws
void <a href="#shared_ptr_swap">swap</a>( shared_ptr&lt;T&gt;&amp; other ) throw()
};
template&lt;typename T, typename U&gt;
inline bool operator==(const shared_ptr&lt;T&gt;&amp; a, const shared_ptr&lt;U&gt;&amp; b)
{ return a.get() == b.get(); }
template&lt;typename T, typename U&gt;
inline bool operator!=(const shared_ptr&lt;T&gt;&amp; a, const shared_ptr&lt;U&gt;&amp; b)
{ return a.get() != b.get(); }
}</pre>
<pre>namespace std {
template&lt;typename T&gt;
inline void swap(boost::shared_ptr&lt;T&gt;&amp; a, boost::shared_ptr&lt;T&gt;&amp; b)
{ a.swap(b); }
template&lt;typename T&gt;
struct less&lt; boost::shared_ptr&lt;T&gt; &gt;
: binary_function&lt;boost::shared_ptr&lt;T&gt;, boost::shared_ptr&lt;T&gt;, bool&gt;
{
bool operator()(const boost::shared_ptr&lt;T&gt;&amp; a,
const boost::shared_ptr&lt;T&gt;&amp; b) const
{ return less&lt;T*&gt;()(a.get(),b.get()); }
};
} // namespace std </pre>
<p>Specialization of std::swap uses the fast, non-throwing swap that's provided
as a member function instead of using the default algorithm which creates a
temporary and uses assignment.<br>
<br>
Specialization of std::less allows use of shared pointers as keys in&nbsp;C++
Standard Library associative collections.<br>
<br>
The std::less specializations use std::less&lt;T*&gt; to perform the
comparison.&nbsp; This insures that pointers are handled correctly, since the
standard mandates that relational operations on pointers are unspecified (5.9 [expr.rel]
paragraph 2) but std::less&lt;&gt; on pointers is well-defined (20.3.3 [lib.comparisons]
paragraph 8).<br>
<br>
It's still a controversial question whether supplying only std::less is better
than supplying a full range of comparison operators (&lt;, &gt;, &lt;=, &gt;=).</p>
<p>The current implementation does not supply the specializations if the macro
name BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION is defined.</p>
<p>The current implementation does not supply the member template functions if
the macro name BOOST_NO_MEMBER_TEMPLATES is defined.</p>
<h2>Class shared_ptr Members</h2>
<h3>shared_ptr <a name="shared_ptr_element_type">element_type</a></h3>
<pre>typedef T element_type;</pre>
<p>Provides the type of the stored pointer.</p>
<h3><a name="shared_ptr_ctor">shared_ptr constructors</a></h3>
<pre>explicit shared_ptr( T* p=0 );</pre>
<p>Constructs a <strong>shared_ptr</strong>, storing a copy of <tt>p</tt>, which
must have been allocated via a C++ <tt>new</tt> expression or be 0. Afterwards, <strong>use_count()</strong>
is 1 (even if p==0; see <a href="#shared_ptr_~shared_ptr">~shared_ptr</a>).</p>
<p>The only exception which may be thrown by this constructor is <tt>std::bad_alloc</tt>.&nbsp;&nbsp;
If an exception is thrown,&nbsp; <tt>delete p</tt> is called.</p>
<pre>shared_ptr( const shared_ptr&amp; r); // never throws
template&lt;typename Y&gt;
shared_ptr(const shared_ptr&lt;Y&gt;&amp; r); // never throws
template&lt;typename Y&gt;
shared_ptr(std::auto_ptr&lt;Y&gt;&amp; r);</pre>
<p>Constructs a <strong>shared_ptr</strong>, as if by storing a copy of the
pointer stored in <strong>r</strong>. Afterwards, <strong>use_count()</strong>
for all copies is 1 more than the initial <strong>r.use_count()</strong>, or 1
in the <strong>auto_ptr</strong> case. In the <strong>auto_ptr</strong> case, <strong>r.release()</strong>
is called.</p>
<p>The only exception which may be thrown by the constructor from <strong>auto_ptr</strong>
is <tt>std::bad_alloc</tt>.&nbsp;&nbsp; If an exception is thrown, that
constructor has no effect.</p>
<h3><a name="shared_ptr_~shared_ptr">shared_ptr destructor</a></h3>
<pre>~shared_ptr();</pre>
<p>If <strong>use_count()</strong> == 1, deletes the object pointed to by the
stored pointer.&nbsp;Otherwise, <strong>use_count()</strong> for any remaining
copies is decremented by 1. Note that in C++&nbsp; <tt>delete</tt> on a pointer
with a value of 0 is harmless.</p>
<p>Does not throw exceptions.</p>
<h3>shared_ptr <a name="shared_ptr_operator=">operator=</a></h3>
<pre>shared_ptr&amp; operator=( const shared_ptr&amp; r);
template&lt;typename Y&gt;
shared_ptr&amp; operator=(const shared_ptr&lt;Y&gt;&amp; r);
template&lt;typename Y&gt;
shared_ptr&amp; operator=(std::auto_ptr&lt;Y&gt;&amp; r);</pre>
<p>First, if <strong>use_count()</strong> == 1, deletes the object pointed to by
the stored pointer.&nbsp;Otherwise, <strong>use_count()</strong> for any
remaining copies is decremented by 1. Note that in C++&nbsp; <tt>delete</tt> on
a pointer with a value of 0 is harmless.</p>
<p>Then replaces the contents of <strong>this</strong>, as if by storing a copy
of the pointer stored in <strong>r</strong>. Afterwards, <strong>use_count()</strong>
for all copies is 1 more than the initial <strong>r.use_count()</strong>, or 1
in the <strong>auto_ptr</strong> case. In the <strong>auto_ptr</strong> case, <strong>r.release()</strong>
is called.</p>
<p>The first two forms of <tt>operator=</tt> above do not throw exceptions.</p>
<p>The only exception which may be thrown by the <strong>auto_ptr</strong> form
is <tt>std::bad_alloc</tt>.&nbsp;&nbsp; If an exception is thrown, the function
has no effect.</p>
<h3>shared_ptr <a name="shared_ptr_reset">reset</a></h3>
<pre>void reset( T* p=0 );</pre>
<p>First, if <strong>use_count()</strong> == 1, deletes the object pointed to by
the stored pointer.&nbsp;Otherwise, <strong>use_count()</strong> for any
remaining copies is decremented by 1.&nbsp;</p>
<p>Then replaces the contents of <strong>this</strong>, as if by storing a copy
of <strong>p</strong>, which must have been allocated via a C++ <tt>new</tt>
expression or be 0. Afterwards, <strong>use_count()</strong> is 1 (even if p==0;
see <a href="#shared_ptr_~shared_ptr">~shared_ptr</a>). Note that in C++&nbsp; <tt>delete</tt>
on a pointer with a value of 0 is harmless.</p>
<p>The only exception which may be thrown is <tt>std::bad_alloc</tt>.&nbsp; If
an exception is thrown,&nbsp; <tt>delete p</tt> is called.</p>
<h3>shared_ptr <a name="shared_ptr_operator*">operator*</a></h3>
<pre>T&amp; operator*() const; // never throws</pre>
<p>Returns a reference to the object pointed to by the stored pointer.</p>
<h3>shared_ptr <a name="shared_ptr_operator-&gt;">operator-&gt;</a> and <a name="shared_ptr_get">get</a></h3>
<pre>T* operator-&gt;() const; // never throws
T* get() const; // never throws</pre>
<p>Both return the stored pointer.</p>
<h3>shared_ptr<a name="shared_ptr_use_count"> use_count</a></h3>
<p><tt>long use_count() const; // never throws</tt></p>
<p>Returns the number of <strong>shared_ptrs</strong> sharing ownership of the
stored pointer.</p>
<h3>shared_ptr <a name="shared_ptr_unique">unique</a></h3>
<p><tt>bool unique() const; // never throws</tt></p>
<p>Returns <strong>use_count()</strong> == 1.</p>
<h3><a name="shared_ptr_swap">shared_ptr swap</a></h3>
<p><code>void swap( shared_ptr&lt;T&gt;&amp; other ) throw()</code></p>
<p>Swaps the two smart pointers, as if by std::swap.</p>
<h2>Class <a name="shared_ptr_example">shared_ptr example</a></h2>
<p>[To be supplied. In the meantime, see <a href="smart_ptr_test.cpp">smart_ptr_test.cpp</a>.]</p>
<hr>
<p>Revised December 8, 1999</p>
<p><EFBFBD> Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use,
modify, sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &quot;as is&quot;
without express or implied warranty, and with no claim as to its suitability for
any purpose.</p>
</body>
</html>

138
smart_ptr.htm Normal file
View File

@ -0,0 +1,138 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Smart Pointer Classes</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Smart
Pointers</h1>
<p>Smart pointers are classes which store pointers to dynamically allocated
(heap) objects.&nbsp; They behave much like built-in C++ pointers except that
they automatically delete the object pointed to at the appropriate
time.&nbsp;Smart pointers are particularly useful in the face of exceptions as
they ensure proper destruction of dynamically allocated objects. They can also
be used to keep track of dynamically allocated objects shared by multiple
owners.</p>
<p>Conceptually, smart pointers are seen as owning the object pointed to, and
thus responsible for deletion of the object when it is no longer needed.</p>
<p>The header <a href="../../boost/smart_ptr.hpp">boost/smart_ptr.hpp</a>
provides four smart pointer template classes:</p>
<div align="left">
<table border="1" cellpadding="4" cellspacing="4">
<tr>
<td>
<p align="left"><a href="scoped_ptr.htm"><strong>scoped_ptr</strong></a></td>
<td>Simple sole ownership of single objects.</td>
</tr>
<tr>
<td><a href="scoped_array.htm"><strong>scoped_array</strong></a></td>
<td>Simple sole ownership of arrays.</td>
</tr>
<tr>
<td><a href="shared_ptr.htm"><strong>shared_ptr</strong></a></td>
<td>Object ownership shared among multiple pointers</td>
</tr>
<tr>
<td><a href="shared_array.htm"><strong>shared_array</strong></a></td>
<td>Array ownership shared among multiple pointers.</td>
</tr>
</table>
</div>
<p>These classes are designed to complement the C++ Standard Library <tt>auto_ptr</tt>
class.</p>
<p>They are examples of the &quot;resource acquisition is initialization&quot;
idiom described in Bjarne Stroustrup's &quot;The C++ Programming Language&quot;,
3rd edition, Section 14.4, Resource Management.</p>
<p>A test program (<a href="smart_ptr_test.cpp">smart_ptr_test.cpp</a>) is
provided to verify correct operation.</p>
<p>A page on <a href="smarttests.htm">Smart Pointer Timings</a> will be of
interest to those curious about performance issues.</p>
<h2><a name="Common requirements">Common requirements</a></h2>
<p>These smart pointer classes have a template parameter, <tt>T</tt>, which
specifies the type of the object pointed to by the smart pointer.&nbsp; The
behavior of all four classes is undefined if the destructor or operator delete
for objects of type <tt>T</tt> throws exceptions.</p>
<h2>Exception safety</h2>
<p>Several functions in these smart pointer classes are specified as having
&quot;no effect&quot; or &quot;no effect except such-and-such&quot; if an
exception is thrown.&nbsp;&nbsp; This means that when an exception is thrown by
an object of one of these classes, the entire program state remains the same as
it was prior to the function call which resulted in the exception being
thrown.&nbsp; This amounts to a guarantee that there are no detectable side
effects.&nbsp;&nbsp; Other functions never throw exceptions. The only exception
ever thrown by functions which do throw (assuming <tt>T</tt> meets the <a href="#Common requirements">Common
requirements</a>)&nbsp; is <tt>std::bad_alloc</tt>, and that is thrown only by
functions which are explicitly documented as possibly throwing <tt>std::bad_alloc</tt>.</p>
<h2>Exception-specifications</h2>
<p>Exception-specifications are not used; see <a href="../../more/lib_guide.htm#Exception-specification">exception-specification
rationale</a>.</p>
<p>All four classes contain member functions which can never throw exceptions,
because they neither throw exceptions themselves nor call other functions which
may throw exceptions.&nbsp; These members are indicated by a comment: <kbd>//
never throws</kbd>. </p>
<p>Functions which destroy objects of the pointed to type are prohibited from
throwing exceptions by the <a href="#Common requirements">Common requirements</a>.</p>
<h2>History and acknowledgements</h2>
<p>November, 1999. Darin Adler provided operator ==, operator !=, and std::swap
and std::less specializations for shared types.</p>
<p>September, 1999. Luis Coelho provided shared_ptr::swap and shared_array::swap</p>
<p>May, 1999.&nbsp; In April and May, 1999, Valentin Bonnard and David Abrahams
made a number of suggestions resulting in numerous improvements.&nbsp; See the
revision history in <a href="../../boost/smart_ptr.hpp"><tt>smart_ptr.hpp</tt></a>
for the specific changes made as a result of their constructive criticism.</p>
<p>Oct, 1998.&nbsp; In 1994 Greg Colvin proposed to the C++ Standards Committee
classes named <strong>auto_ptr</strong> and <strong>counted_ptr</strong> which
were very similar to what we now call <strong>scoped_ptr</strong> and <strong>shared_ptr</strong>.&nbsp;
The committee document was 94-168/N0555, Exception Safe Smart Pointers.&nbsp; In
one of the very few cases where the Library Working Group's recommendations were
not followed by the full committee, <strong>counted_ptr</strong> was rejected
and surprising transfer-of-ownership semantics were added to <strong>auto-ptr</strong>.</p>
<p>Beman Dawes proposed reviving the original semantics under the names <strong>safe_ptr</strong>
and <strong>counted_ptr</strong> at an October, 1998, meeting of Per Andersson,
Matt Austern, Greg Colvin, Sean Corfield, Pete Becker, Nico Josuttis, Dietmar
K<EFBFBD>hl, Nathan Myers, Chichiang Wan and Judy Ward.&nbsp; During the discussion,
the four class names were finalized, it was decided that there was no need to
exactly follow the <strong>std::auto_ptr</strong> interface, and various
function signatures and semantics were finalized.</p>
<p>Over the next three months, several implementations were considered for <strong>shared_ptr</strong>,
and discussed on the <a href="http://www.boost.org">boost.org</a> mailing
list.&nbsp; The implementation questions revolved around the reference count
which must be kept, either attached to the pointed to object, or detached
elsewhere. Each of those variants have themselves two major variants:
<ul>
<li>Direct detached: the shared_ptr contains a pointer to the object, and a
pointer to the count.</li>
<li>Indirect detached: the shared_ptr contains a pointer to a helper object,
which in turn contains a pointer to the object and the count.</li>
<li>Embedded attached: the count is a member of the object pointed to.</li>
<li>Placement attached: the count is attached via operator new manipulations.</li>
</ul>
<p>Each implementation technique has advantages and disadvantages.&nbsp; We went
so far as to run various timings of the direct and indirect approaches, and
found that at least on Intel Pentium chips there was very little measurable
difference.&nbsp; Kevlin Henney provided a paper he wrote on &quot;Counted Body
Techniques.&quot;&nbsp; Dietmar K<>hl suggested an elegant partial template
specialization technique to allow users to choose which implementation they
preferred, and that was also experimented with.</p>
<p>But Greg Colvin and Jerry Schwarz argued that &quot;parameterization will
discourage users&quot;, and in the end we choose to supply only the direct
implementation.</p>
<p>See the Revision History section of the header for further contributors.</p>
<hr>
<p>Revised&nbsp; <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan
-->24 Jul 2000<!--webbot bot="Timestamp" endspan i-checksum="14986"
--></p>
<p><EFBFBD> Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use,
modify, sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &quot;as is&quot;
without express or implied warranty, and with no claim as to its suitability for
any purpose.</p>
</body>
</html>

540
smarttests.htm Normal file
View File

@ -0,0 +1,540 @@
<html>
<head>
<title>boost: smart pointer tests</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<!--
-->
<body bgcolor="#FFFFFF">
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" WIDTH="277" HEIGHT="86">Smart
Pointers Timings </h1>
<p>In late January 2000, Mark Borgerding put forward a suggestion to boost for
a new design of smart pointer whereby an intrusive doubly linked list is used
to join together all instances of smart pointers sharing a given raw pointer.
This allowed avoidance of the costly heap allocation of a reference count that
occurred in the initial construction of the then current version of boost::shared_ptr.
Of course, nothing is for free and the benefit here was gained at the expense
of increased size and more costly copy operations. A debate ensued on the boost
mailing list and the tests which this page describes were performed to provide
a guide for current and future investigations into smart pointer implementation
strategies.</p>
<p>Thanks are due to <a href="../../people/dave_abrahams.htm"> Dave Abrahams</a>,
<a href="../../people/gavin_collings.htm"> Gavin Collings</a>, <a href="../../people/greg_colvin.htm"> Greg Colvin</a> and
<a href="../../people/beman_dawes.html"> Beman Dawes</a>
for test code and trial implementations, the final version of which can be found
in .zip format <a href="smarttest.zip">here</a>.</p>
<h2>Description</h2>
<p>Two tests were run: the first aimed to obtain timings for two basic individual
operations:</p>
<ol type="i">
<li> Initial construction from raw pointer.</li>
<li> An amortized copy operation consisting of half an assignment and half a
copy construction - designed to reflect average usage.</li>
</ol>
<p>The second attempted to gain more insight into normal usage by timing the fill
and sort algorithms for vectors and lists filled with the various smart pointers.</p>
<p>Five smart pointer implementation strategies were tested:</p>
<ol type="i">
<li>Counted pointer using a heap allocated reference count, this is referred
to as <b>simple counted</b>.</li>
<li>Counted pointer using a special purpose allocator for the reference count
- <b>special counted</b>.</li>
<li>Counted pointer using an intrusive reference count - <b>intrusive</b>.</li>
<li>Linked pointer as described above - <b>linked</b>.</li>
<li>Cyclic pointer, a counted implementation using a std::deque for allocation
with provision for weak pointers and garbage collection of cycles of pointers
- <b>cyclic</b>.</li>
</ol>
<p>on two compilers:</p>
<ol type="i">
<li>MSVC 6.0 service pack 3, using default release optimization mode (/O2 -
optimized for speed, no inlining of functions defined outside a class body
unless specified as inline).</li>
<li>gcc 2.95.2 using full optimization (-O3 -DNDEBUG).</li>
</ol>
<p>Additionally, generated pointer sizes (taking into account struct alignment)
were compared, as were generated code sizes for MSVC mainly by manual inspection
of generated assembly code - a necessity due to function inlining.</p>
<p>All tests were run on a PII-200 running Windows NT version 4.0</p>
<h2>&nbsp;</h2>
<h2>Operation Timing Test Results</h2>
<p>The following graphs show the overall time in nanoseconds to acquire a pointer
(default construction) perform n amortized copy operations on it and finally
release it. The initial allocation time for the contained pointer is not included,
although the time for it's deallocation is. The contained pointer pointed to
a trivial class, but for the inclusion of an intrusive reference count for the
benefit of the intrusive counted shared pointer. A dumb pointer (i.e. a smart
pointer that simply acquires and releases its contained pointer with no extra
overhead) and a raw pointer were also included for comparison.</p>
<table border="0" align="center">
<tr>
<td width="20" height="20">&nbsp;</td>
<td>&nbsp;</td>
<td width="20">&nbsp;</td>
</tr>
<tr>
<td width="20">&nbsp; </td>
<td><img src="msvcspeed.gif" width="560" height="355"></td>
<td width="20">&nbsp;</td>
</tr>
<tr>
<td height="20">&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td><img src="gccspeed.gif" width="560" height="355"></td>
<td>&nbsp;</td>
</tr>
<tr>
<td height="20">&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</table>
<p>&nbsp;</p>
<p>Fitting straight lines to the above plots gives the following figures for initialization
and amortized copy operation for the two compilers (times in nanoseconds, errors
at two standard deviations) : -</p>
<p>&nbsp;</p>
<h4 align="center">MSVC</h4>
<table align="center" cellpadding="5" cellspacing="0" class="codetable" width="400">
<tr>
<th width="120">
<div align="right"></div>
</th>
<th class="codetabletop" width="120">
<div align="center">initialization</div>
</th>
<th class="codetabletop" width="120">copy operation</th>
</tr>
<tr>
<th class="codetableleft">
<div align="right">simple counted</div>
</th>
<td class="codetablecell" align="center">3000 +/- 170</td>
<td class="codetablecell" align="center">104 +/- 31</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">special counted</div>
</th>
<td class="codetablecell" align="center">1330 +/- 50</td>
<td class="codetablecell" align="center">85 +/- 9</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">intrusive</div>
</th>
<td class="codetablecell" align="center">1000 +/- 20</td>
<td class="codetablecell" align="center">71 +/- 3</td>
</tr>
<tr>
<th class="codetableleft" align="right">linked</th>
<td class="codetablecell" align="center">970 +/- 60</td>
<td class="codetablecell" align="center">136 +/- 10</td>
</tr>
<tr>
<th class="codetableleft" align="right">cyclic</th>
<td class="codetablecell" align="center">1290 +/- 70</td>
<td class="codetablecell" align="center">112 +/- 12</td>
</tr>
<tr>
<th class="codetableleft" align="right">dumb</th>
<td class="codetablecell" align="center">1020 +/- 20</td>
<td class="codetablecell" align="center">10 +/- 4</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">raw</div>
</th>
<td class="codetablecell" align="center">1038 +/- 30</td>
<td class="codetablecell" align="center">10 +/- 5</td>
</tr>
</table>
<h4 align="center">&nbsp;</h4>
<h4 align="center">GCC</h4>
<table align="center" cellpadding="5" cellspacing="0" class="codetable" width="400">
<tr>
<th width="120">
<div align="right"></div>
</th>
<th class="codetabletop" width="120">
<div align="center">initialization</div>
</th>
<th class="codetabletop" width="120">copy operation</th>
</tr>
<tr>
<th class="codetableleft">
<div align="right">simple counted</div>
</th>
<td class="codetablecell" align="center">4620 +/- 150</td>
<td class="codetablecell" align="center">301 +/- 28</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">special counted</div>
</th>
<td class="codetablecell" align="center">1990 +/- 40</td>
<td class="codetablecell" align="center">264 +/- 7</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">intrusive</div>
</th>
<td class="codetablecell" align="center">1590 +/- 70</td>
<td class="codetablecell" align="center">181 +/- 12</td>
</tr>
<tr>
<th class="codetableleft" align="right">linked</th>
<td class="codetablecell" align="center">1470 +/- 140</td>
<td class="codetablecell" align="center">345 +/- 26</td>
</tr>
<tr>
<th class="codetableleft" align="right">cyclic</th>
<td class="codetablecell" align="center">2180 +/- 100</td>
<td class="codetablecell" align="center">330 +/- 18</td>
</tr>
<tr>
<th class="codetableleft" align="right">dumb</th>
<td class="codetablecell" align="center">1590 +/- 70</td>
<td class="codetablecell" align="center">74 +/- 12</td>
</tr>
<tr>
<th class="codetableleft" align="right">
<div align="right">raw</div>
</th>
<td class="codetablecell" align="center">1430 +/- 60</td>
<td class="codetablecell" align="center">27 +/- 11</td>
</tr>
</table>
<p>Note that the above times include a certain amount of loop overhead etc. for
each operation. An estimate of the pure smart pointer operation time 'overhead'
can be obtained by subtracting the dumb or raw figure from the smart pointer
time of interest.</p>
<h3>Detail</h3>
<p>The test involved iterating a loop which creates raw pointers. These were then
shared among a varying number (set size) of smart pointers. A range of set sizes
was used and then a line fitted to get a linear relation with number of initializations
and copy-operations. A spreadsheet was used for the line fit, and to produce
the performance graphs above.</p>
<h2>&nbsp;</h2>
<h2>Container Test Results</h2>
<p>To gain some insight in to operation within real life programs, this test was
devised. Smart pointers were used to fill standard containers which were then
sorted.</p>
<p>In this case, the contained pointer pointed to a class which initializes a
private data member to a random value in its default constructor. This value
is used subsequently for the sort comparison test. The class also contains an
intrusive reference count for the benefit of the intrusive counted pointer.</p>
<p> All times are in seconds for 300,000 contained pointers.</p>
<h4 align="center">GCC</h4>
<table align="center" cellpadding="5" cellspacing="0" class="codetable" width="500">
<tr>
<th>&nbsp;</th>
<th class="codetabletop" colspan="2">vector</th>
<th class="codetabletop" colspan="2">list</th>
</tr>
<tr>
<th width="120">
<div align="right"></div>
</th>
<th class="codetabletop2" width="80">
<div align="center">fill</div>
</th>
<th class="codetabletop2" width="80">sort</th>
<th class="codetabletop2" width="80">fill</th>
<th class="codetabletop2" width="80">sort</th>
</tr>
<tr>
<th class="codetableleft">
<div align="right">simple counted</div>
</th>
<td class="codetablecell" align="center">46.54</td>
<td class="codetablecell" align="center">2.44</td>
<td class="codetablecell" align="center">47.09</td>
<td class="codetablecell" align="center">3.22</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">special counted</div>
</th>
<td class="codetablecell" align="center">14.02</td>
<td class="codetablecell" align="center">2.83</td>
<td class="codetablecell" align="center">7.28</td>
<td class="codetablecell" align="center">3.21</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">intrusive</div>
</th>
<td class="codetablecell" align="center">12.15</td>
<td class="codetablecell" align="center">1.91</td>
<td class="codetablecell" align="center">7.99</td>
<td class="codetablecell" align="center">3.08</td>
</tr>
<tr>
<th class="codetableleft" align="right">linked</th>
<td class="codetablecell" align="center">12.46</td>
<td class="codetablecell" align="center">2.32</td>
<td class="codetablecell" align="center">8.14</td>
<td class="codetablecell" align="center">3.27</td>
</tr>
<tr>
<th class="codetableleft" align="right">cyclic</th>
<td class="codetablecell" align="center">22.60</td>
<td class="codetablecell" align="center">3.19</td>
<td class="codetablecell" align="center">1.63</td>
<td class="codetablecell" align="center">3.18</td>
</tr>
<tr>
<th class="codetableleft" align="right">
<div align="right">raw</div>
</th>
<td class="codetablecell" align="center">11.81</td>
<td class="codetablecell" align="center">0.24</td>
<td class="codetablecell" align="center">27.51</td>
<td class="codetablecell" align="center">0.77</td>
</tr>
</table>
<p>&nbsp;</p>
<h4 align="center">MSVC</h4>
<table align="center" cellpadding="5" cellspacing="0" class="codetable" width="500">
<tr>
<th>&nbsp;</th>
<th class="codetabletop" colspan="2">vector</th>
<th class="codetabletop" colspan="2">list</th>
</tr>
<tr>
<th width="120">
<div align="right"></div>
</th>
<th class="codetabletop2" width="80">
<div align="center">fill</div>
</th>
<th class="codetabletop2" width="80">sort</th>
<th class="codetabletop2" width="80">fill</th>
<th class="codetabletop2" width="80">sort</th>
</tr>
<tr>
<th class="codetableleft">
<div align="right">simple counted</div>
</th>
<td class="codetablecell" align="center">1.83</td>
<td class="codetablecell" align="center">2.37</td>
<td class="codetablecell" align="center">1.86</td>
<td class="codetablecell" align="center">4.85</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">special counted</div>
</th>
<td class="codetablecell" align="center">1.04</td>
<td class="codetablecell" align="center">2.35</td>
<td class="codetablecell" align="center">1.38</td>
<td class="codetablecell" align="center">4.58</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">intrusive</div>
</th>
<td class="codetablecell" align="center">1.04</td>
<td class="codetablecell" align="center">1.84</td>
<td class="codetablecell" align="center">1.16</td>
<td class="codetablecell" align="center">4.29</td>
</tr>
<tr>
<th class="codetableleft" align="right">linked</th>
<td class="codetablecell" align="center">1.08</td>
<td class="codetablecell" align="center">2.00</td>
<td class="codetablecell" align="center">1.21</td>
<td class="codetablecell" align="center">4.33</td>
</tr>
<tr>
<th class="codetableleft" align="right">cyclic</th>
<td class="codetablecell" align="center">1.38</td>
<td class="codetablecell" align="center">2.84</td>
<td class="codetablecell" align="center">1.47</td>
<td class="codetablecell" align="center">4.73</td>
</tr>
<tr>
<th class="codetableleft" align="right">
<div align="right">raw</div>
</th>
<td class="codetablecell" align="center">0.67</td>
<td class="codetablecell" align="center">0.28</td>
<td class="codetablecell" align="center">1.24</td>
<td class="codetablecell" align="center">1.81</td>
</tr>
</table>
<p>&nbsp;</p>
<h2>Code Size</h2>
<p>The following code sizes were determined by inspection of generated code for
MSVC only. Sizes are given in the form N / M / I where:</p>
<ul type="circle">
<li> N is the instruction count of the operation</li>
<li>M is the size of the code in bytes</li>
<li>I determines whether generated code was inlined or not I = inline, O = &quot;outline&quot;</li>
</ul>
<p>&nbsp;</p>
<table align="center" cellpadding="5" cellspacing="0" class="codetable" width="570">
<tr>
<th height="28" width="140">
<div align="right"></div>
</th>
<th height="28" class="codetabletop" width="80">
<div align="center">ptr()</div>
</th>
<th height="28" class="codetabletop" width="80">ptr(p)</th>
<th height="28" class="codetabletop" width="80">ptr(ptr)</th>
<th height="28" class="codetabletop" width="80">op=()</th>
<th height="28" class="codetabletop" width="80">
<div align="center">~ptr()</div>
</th>
</tr>
<tr>
<th class="codetableleft">
<div align="right">simple counted</div>
</th>
<td class="codetablecell" align="center">38/110/O</td>
<td class="codetablecell" align="center">38/110/O</td>
<td class="codetablecell" align="center">9/23/I</td>
<td class="codetablecell" align="center">22/57/I</td>
<td class="codetablecell" align="center">17/40/I</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">special counted</div>
</th>
<td class="codetablecell" align="center"><font size="-1">50/141/O</font></td>
<td class="codetablecell" align="center"><font size="-1">50/141/O</font></td>
<td class="codetablecell" align="center"><font size="-1">9/23/I</font></td>
<td class="codetablecell" align="center"><font size="-1">23/64/I</font></td>
<td class="codetablecell" align="center"><font size="-1">13/38/I</font></td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">intrusive</div>
</th>
<td class="codetablecell" align="center"><font size="-1">1/2/I</font></td>
<td class="codetablecell" align="center"><font size="-1">3/6/I</font></td>
<td class="codetablecell" align="center"><font size="-1">3/6/I</font></td>
<td class="codetablecell" align="center"><font size="-1">6/11/I</font></td>
<td class="codetablecell" align="center"><font size="-1">6/11/I</font></td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">linked</div>
</th>
<td class="codetablecell" align="center"><font size="-1">5/19/I</font></td>
<td class="codetablecell" align="center"><font size="-1">5/15/I</font></td>
<td class="codetablecell" align="center"><font size="-1">10/30/I</font></td>
<td class="codetablecell" align="center"><font size="-1">27/59/I</font></td>
<td class="codetablecell" align="center"><font size="-1">14/38/I</font></td>
</tr>
</table>
<p>During the code inspection, a couple of minor points were noticed: -</p>
<ul>
<li>Function inlining was critical to performance.</li>
<li>For MSVC, at least, a &quot;delete 0&quot; caused execution of 11 assembly
instructions, including a function call. So in cases where performance is
at an absolute premium it can be worth inserting the extra manual test.</li>
</ul>
<h2>&nbsp;</h2>
<h2>Data Size</h2>
<p>The following smart pointer sizes were obtained in bytes</p>
<table align="center" cellpadding="5" cellspacing="0" class="codetable" width="270">
<tr>
<th height="28" width="150">
<div align="right"></div>
</th>
<th height="28" class="codetabletop" width="60">
<div align="center">MSVC</div>
</th>
<th height="28" class="codetabletop" width="60">
<div align="center">GCC</div>
</th>
</tr>
<tr>
<th class="codetableleft">
<div align="right">simple counted</div>
</th>
<td class="codetablecell">
<div align="center">8</div>
</td>
<td class="codetablecell">
<div align="center">8</div>
</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">special counted</div>
</th>
<td class="codetablecell">
<div align="center">8</div>
</td>
<td class="codetablecell">
<div align="center">12</div>
</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">intrusive</div>
</th>
<td class="codetablecell">
<div align="center">4</div>
</td>
<td class="codetablecell">
<div align="center">4</div>
</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">linked</div>
</th>
<td class="codetablecell">
<div align="center">12</div>
</td>
<td class="codetablecell">
<div align="center">12</div>
</td>
</tr>
<tr>
<th class="codetableleft">
<div align="right">cyclic</div>
</th>
<td class="codetablecell">
<div align="center">8</div>
</td>
<td class="codetablecell">
<div align="center">8</div>
</td>
</tr>
</table>
<h2>&nbsp;</h2>
<h2>Summary</h2>
<p>The timing results mainly speak for themselves: clearly an intrusive pointer
outperforms all others and a simple heap based counted pointer has poor performance
relative to other implementations. The selection of an optimal non-intrusive
smart pointer implementation is more application dependent, however. Where small
numbers of copies are expected, it is likely that the linked implementation
will be favoured. Conversely, for larger numbers of copies a counted pointer
with some type of special purpose allocator looks like a win. Other factors
to bear in mind are: -</p>
<ul>
<li>Deterministic individual, as opposed to amortized, operation time. This
weighs against any implementation depending on an allocator.</li>
<li>Multithreaded synchronization. This weighs against an implementation which
spreads its information as in the case of linked pointer.</li>
</ul>
<hr>
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %b %Y" startspan -->21 Feb 2000<!--webbot bot="Timestamp" endspan i-checksum="14372" -->
</p>
<p><EFBFBD> Copyright Gavin Collings 2000. Permission to copy, use, modify, sell
and distribute this document is granted provided this copyright notice appears in all
copies. This document is provided &quot;as is&quot; without express or implied warranty,
and with no claim as to its suitability for any purpose.</p>
</body>
</html>