This commit was manufactured by cvs2svn to create tag

'Version_1_24_0'.

[SVN r10904]
This commit is contained in:
nobody
2001-08-20 14:01:13 +00:00
19 changed files with 2343 additions and 0 deletions

BIN
gccspeed.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

402
include/boost/smart_ptr.hpp Normal file
View File

@ -0,0 +1,402 @@
// Boost smart_ptr.hpp header file -----------------------------------------//
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. Permission to copy,
// use, modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided "as is"
// without express or implied warranty, and with no claim as to its
// suitability for any purpose.
// See http://www.boost.org for most recent version including documentation.
// Revision History
// 6 Jul 01 Reorder shared_ptr code so VC++ 6 member templates work, allowing
// polymorphic pointers to now work with that compiler (Gary Powell)
// 21 May 01 Require complete type where incomplete type is unsafe.
// (suggested by Vladimir Prus)
// 21 May 01 operator= fails if operand transitively owned by *this, as in a
// linked list (report by Ken Johnson, fix by Beman Dawes)
// 21 Jan 01 Suppress some useless warnings with MSVC (David Abrahams)
// 19 Oct 00 Make shared_ptr ctor from auto_ptr explicit. (Robert Vugts)
// 24 Jul 00 Change throw() to // never throws. See lib guidelines
// Exception-specification rationale. (Beman Dawes)
// 22 Jun 00 Remove #if continuations to fix GCC 2.95.2 problem (Beman Dawes)
// 1 Feb 00 Additional shared_ptr BOOST_NO_MEMBER_TEMPLATES workarounds
// (Dave Abrahams)
// 31 Dec 99 Condition tightened for no member template friend workaround
// (Dave Abrahams)
// 30 Dec 99 Moved BOOST_NMEMBER_TEMPLATES compatibility code to config.hpp
// (Dave Abrahams)
// 30 Nov 99 added operator ==, operator !=, and std::swap and std::less
// specializations for shared types (Darin Adler)
// 11 Oct 99 replaced op[](int) with op[](std::size_t) (Ed Brey, Valentin
// Bonnard), added shared_ptr workaround for no member template
// friends (Matthew Langston)
// 25 Sep 99 added shared_ptr::swap and shared_array::swap (Luis Coelho).
// 20 Jul 99 changed name to smart_ptr.hpp, #include <boost/config.hpp>,
// #include <boost/utility.hpp> and use boost::noncopyable
// 17 May 99 remove scoped_array and shared_array operator*() as
// unnecessary (Beman Dawes)
// 14 May 99 reorder code so no effects when bad_alloc thrown (Abrahams/Dawes)
// 13 May 99 remove certain throw() specifiers to avoid generated try/catch
// code cost (Beman Dawes)
// 11 May 99 get() added, conversion to T* placed in macro guard (Valentin
// Bonnard, Dave Abrahams, and others argued for elimination
// of the automatic conversion)
// 28 Apr 99 #include <memory> fix (Valentin Bonnard)
// 28 Apr 99 rename transfer() to share() for clarity (Dave Abrahams)
// 28 Apr 99 remove unsafe shared_array template conversions(Valentin Bonnard)
// 28 Apr 99 p(r) changed to p(r.px) for clarity (Dave Abrahams)
// 21 Apr 99 reset() self assignment fix (Valentin Bonnard)
// 21 Apr 99 dispose() provided to improve clarity (Valentin Bonnard)
// 27 Apr 99 leak when new throws fixes (Dave Abrahams)
// 21 Oct 98 initial Version (Greg Colvin/Beman Dawes)
#ifndef BOOST_SMART_PTR_HPP
#define BOOST_SMART_PTR_HPP
#include <boost/config.hpp> // for broken compiler workarounds
#include <cstddef> // for std::size_t
#include <memory> // for std::auto_ptr
#include <algorithm> // for std::swap
#include <boost/utility.hpp> // for boost::noncopyable, checked_delete, checked_array_delete
#include <functional> // for std::less
#include <boost/static_assert.hpp> // for BOOST_STATIC_ASSERT
#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash
# pragma warning(push)
# pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation
#endif
namespace boost {
// scoped_ptr --------------------------------------------------------------//
// scoped_ptr mimics a built-in pointer except that it guarantees deletion
// of the object pointed to, either on destruction of the scoped_ptr or via
// an explicit reset(). scoped_ptr is a simple solution for simple needs;
// see shared_ptr (below) or std::auto_ptr if your needs are more complex.
template<typename T> class scoped_ptr : noncopyable {
T* ptr;
public:
typedef T element_type;
explicit scoped_ptr( T* p=0 ) : ptr(p) {} // never throws
~scoped_ptr() { checked_delete(ptr); }
void reset( T* p=0 ) { if ( ptr != p ) { checked_delete(ptr); ptr = p; } }
T& operator*() const { return *ptr; } // never throws
T* operator->() const { return ptr; } // never throws
T* get() const { return ptr; } // never throws
#ifdef BOOST_SMART_PTR_CONVERSION
// get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
operator T*() const { return ptr; } // never throws
#endif
}; // scoped_ptr
// scoped_array ------------------------------------------------------------//
// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
// is guaranteed, either on destruction of the scoped_array or via an explicit
// reset(). See shared_array or std::vector if your needs are more complex.
template<typename T> class scoped_array : noncopyable {
T* ptr;
public:
typedef T element_type;
explicit scoped_array( T* p=0 ) : ptr(p) {} // never throws
~scoped_array() { checked_array_delete(ptr); }
void reset( T* p=0 ) { if ( ptr != p )
{checked_array_delete(ptr); ptr=p;} }
T* get() const { return ptr; } // never throws
#ifdef BOOST_SMART_PTR_CONVERSION
// get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
operator T*() const { return ptr; } // never throws
#else
T& operator[](std::size_t i) const { return ptr[i]; } // never throws
#endif
}; // scoped_array
// shared_ptr --------------------------------------------------------------//
// An enhanced relative of scoped_ptr with reference counted copy semantics.
// The object pointed to is deleted when the last shared_ptr pointing to it
// is destroyed or reset.
template<typename T> class shared_ptr {
public:
typedef T element_type;
explicit shared_ptr(T* p =0) : px(p) {
try { pn = new long(1); } // fix: prevent leak if new throws
catch (...) { checked_delete(p); throw; }
}
~shared_ptr() { dispose(); }
#if !defined( BOOST_NO_MEMBER_TEMPLATES ) || defined (BOOST_MSVC6_MEMBER_TEMPLATES)
template<typename Y>
shared_ptr(const shared_ptr<Y>& r) : px(r.px) { // never throws
++*(pn = r.pn);
}
#ifndef BOOST_NO_AUTO_PTR
template<typename Y>
explicit shared_ptr(std::auto_ptr<Y>& r) {
pn = new long(1); // may throw
px = r.release(); // fix: moved here to stop leak if new throws
}
#endif
template<typename Y>
shared_ptr& operator=(const shared_ptr<Y>& r) {
share(r.px,r.pn);
return *this;
}
#ifndef BOOST_NO_AUTO_PTR
template<typename Y>
shared_ptr& operator=(std::auto_ptr<Y>& r) {
// code choice driven by guarantee of "no effect if new throws"
if (*pn == 1) { checked_delete(px); }
else { // allocate new reference counter
long * tmp = new long(1); // may throw
--*pn; // only decrement once danger of new throwing is past
pn = tmp;
} // allocate new reference counter
px = r.release(); // fix: moved here so doesn't leak if new throws
return *this;
}
#endif
#else
#ifndef BOOST_NO_AUTO_PTR
explicit shared_ptr(std::auto_ptr<T>& r) {
pn = new long(1); // may throw
px = r.release(); // fix: moved here to stop leak if new throws
}
shared_ptr& operator=(std::auto_ptr<T>& r) {
// code choice driven by guarantee of "no effect if new throws"
if (*pn == 1) { checked_delete(px); }
else { // allocate new reference counter
long * tmp = new long(1); // may throw
--*pn; // only decrement once danger of new throwing is past
pn = tmp;
} // allocate new reference counter
px = r.release(); // fix: moved here so doesn't leak if new throws
return *this;
}
#endif
#endif
// The assignment operator and the copy constructor must come after
// the templated versions for MSVC6 to work. (Gary Powell)
shared_ptr(const shared_ptr& r) : px(r.px) { ++*(pn = r.pn); } // never throws
shared_ptr& operator=(const shared_ptr& r) {
share(r.px,r.pn);
return *this;
}
void reset(T* p=0) {
if ( px == p ) return; // fix: self-assignment safe
if (--*pn == 0) { checked_delete(px); }
else { // allocate new reference counter
try { pn = new long; } // fix: prevent leak if new throws
catch (...) {
++*pn; // undo effect of --*pn above to meet effects guarantee
checked_delete(p);
throw;
} // catch
} // allocate new reference counter
*pn = 1;
px = p;
} // reset
T& operator*() const { return *px; } // never throws
T* operator->() const { return px; } // never throws
T* get() const { return px; } // never throws
#ifdef BOOST_SMART_PTR_CONVERSION
// get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
operator T*() const { return px; } // never throws
#endif
long use_count() const { return *pn; } // never throws
bool unique() const { return *pn == 1; } // never throws
void swap(shared_ptr<T>& other) // never throws
{ std::swap(px,other.px); std::swap(pn,other.pn); }
// Tasteless as this may seem, making all members public allows member templates
// to work in the absence of member template friends. (Matthew Langston)
// Don't split this line into two; that causes problems for some GCC 2.95.2 builds
#if ( defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) ) || !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
private:
#endif
T* px; // contained pointer
long* pn; // ptr to reference counter
// Don't split this line into two; that causes problems for some GCC 2.95.2 builds
#if !defined( BOOST_NO_MEMBER_TEMPLATES ) && !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
template<typename Y> friend class shared_ptr;
#endif
void dispose() { if (--*pn == 0) { checked_delete(px); delete pn; } }
void share(T* rpx, long* rpn) {
if (pn != rpn) { // Q: why not px != rpx? A: fails when both == 0
++*rpn; // done before dispose() in case rpn transitively
// dependent on *this (bug reported by Ken Johnson)
dispose();
px = rpx;
pn = rpn;
}
} // share
}; // shared_ptr
template<typename T, typename U>
inline bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b)
{ return a.get() == b.get(); }
template<typename T, typename U>
inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b)
{ return a.get() != b.get(); }
// shared_array ------------------------------------------------------------//
// shared_array extends shared_ptr to arrays.
// The array pointed to is deleted when the last shared_array pointing to it
// is destroyed or reset.
template<typename T> class shared_array {
public:
typedef T element_type;
explicit shared_array(T* p =0) : px(p) {
try { pn = new long(1); } // fix: prevent leak if new throws
catch (...) { checked_array_delete(p); throw; }
}
shared_array(const shared_array& r) : px(r.px) // never throws
{ ++*(pn = r.pn); }
~shared_array() { dispose(); }
shared_array& operator=(const shared_array& r) {
if (pn != r.pn) { // Q: why not px != r.px? A: fails when both px == 0
++*r.pn; // done before dispose() in case r.pn transitively
// dependent on *this (bug reported by Ken Johnson)
dispose();
px = r.px;
pn = r.pn;
}
return *this;
} // operator=
void reset(T* p=0) {
if ( px == p ) return; // fix: self-assignment safe
if (--*pn == 0) { checked_array_delete(px); }
else { // allocate new reference counter
try { pn = new long; } // fix: prevent leak if new throws
catch (...) {
++*pn; // undo effect of --*pn above to meet effects guarantee
checked_array_delete(p);
throw;
} // catch
} // allocate new reference counter
*pn = 1;
px = p;
} // reset
T* get() const { return px; } // never throws
#ifdef BOOST_SMART_PTR_CONVERSION
// get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
operator T*() const { return px; } // never throws
#else
T& operator[](std::size_t i) const { return px[i]; } // never throws
#endif
long use_count() const { return *pn; } // never throws
bool unique() const { return *pn == 1; } // never throws
void swap(shared_array<T>& other) // never throws
{ std::swap(px,other.px); std::swap(pn,other.pn); }
private:
T* px; // contained pointer
long* pn; // ptr to reference counter
void dispose() { if (--*pn == 0) { checked_array_delete(px); delete pn; } }
}; // shared_array
template<typename T>
inline bool operator==(const shared_array<T>& a, const shared_array<T>& b)
{ return a.get() == b.get(); }
template<typename T>
inline bool operator!=(const shared_array<T>& a, const shared_array<T>& b)
{ return a.get() != b.get(); }
} // namespace boost
// specializations for things in namespace std -----------------------------//
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
namespace std {
// Specialize std::swap to use 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.
template<typename T>
inline void swap(boost::shared_ptr<T>& a, boost::shared_ptr<T>& b)
{ a.swap(b); }
template<typename T>
inline void swap(boost::shared_array<T>& a, boost::shared_array<T>& b)
{ a.swap(b); }
// Specialize std::less so we can use shared pointers and arrays as keys in
// associative collections.
// It's still a controversial question whether this is better than supplying
// a full range of comparison operators (<, >, <=, >=).
template<typename T>
struct less< boost::shared_ptr<T> >
: binary_function<boost::shared_ptr<T>, boost::shared_ptr<T>, bool>
{
bool operator()(const boost::shared_ptr<T>& a,
const boost::shared_ptr<T>& b) const
{ return less<T*>()(a.get(),b.get()); }
};
template<typename T>
struct less< boost::shared_array<T> >
: binary_function<boost::shared_array<T>, boost::shared_array<T>, bool>
{
bool operator()(const boost::shared_array<T>& a,
const boost::shared_array<T>& b) const
{ return less<T*>()(a.get(),b.get()); }
};
} // namespace std
#endif // ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
#endif // BOOST_SMART_PTR_HPP

38
index.htm Normal file
View File

@ -0,0 +1,38 @@
<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">
<meta name="ProgId" content="FrontPage.Editor.Document">
</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/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.hpp 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>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 <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->14 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14885" -->
</p>
</body>
</html>

BIN
msvcspeed.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

102
scoped_array.htm Normal file
View File

@ -0,0 +1,102 @@
<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 supplies a basic &quot;resource acquisition is
initialization&quot; facility, without shared-ownership or transfer-of-ownership
semantics.&nbsp; Both its name and enforcement of semantics (by being <a href="../utility/utility.htm#class noncopyable">noncopyable</a>)
signal its intent to retain ownership solely within the current scope.&nbsp; By
being <a href="../utility/utility.htm#class noncopyable">noncopyable</a>, it is
safer than <b>shared_array</b> for pointers which should not be copied.</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 it has no
more space overhead that a built-in array pointer.</p>
<p>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>A C++ Standard Library <strong>vector</strong> is a <strong> </strong>heavier duty alternative to a <strong>scoped_array</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;<a href="../../boost/smart_ptr.hpp">boost/smart_ptr.hpp</a>&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>
<p><b>T</b> is not required be a complete type.&nbsp;
See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</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><b>T</b> is not required be a complete type.&nbsp;
See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p>
<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; <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan
-->24 May, 2001<!--webbot bot="Timestamp" endspan i-checksum="13964"
-->
</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>

153
scoped_ptr.htm Normal file
View File

@ -0,0 +1,153 @@
<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 supplies a basic &quot;resource acquisition is
initialization&quot; facility, without shared-ownership or transfer-of-ownership
semantics.&nbsp; Both its name and enforcement of semantics (by being <a href="../utility/utility.htm#class noncopyable">noncopyable</a>)
signal its intent to retain ownership solely within the current scope.&nbsp;
Because it is <a href="../utility/utility.htm#class noncopyable">noncopyable</a>, it is
safer than <b>shared_ptr</b> or <b> std::auto_ptr</b> for pointers which should not be
copied.</p>
<p>Because <strong>scoped_ptr</strong> is so simple, in its usual implementation
every operation is as fast as for a built-in pointer and it has no more space overhead
that a built-in pointer.&nbsp; (Because of the &quot;complete type&quot;
requirement for delete and reset members, they may have one additional function
call overhead in certain idioms.&nbsp; See <a href="#Handle/Body">Handle/Body
Idiom</a>.)&nbsp;&nbsp;&nbsp;</p>
<p>Class<strong> scoped_ptr</strong> 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>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;<a href="../../boost/smart_ptr.hpp">boost/smart_ptr.hpp</a>&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><b>T</b> is not required be a complete type.&nbsp;
See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p>
<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><b>T</b> is not required by get() be a complete type.&nbsp; See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p>
<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>Rationale</h2>
<p>The primary reason to use <b> scoped_ptr</b> rather than <b> auto_ptr</b> is to let readers
of your code know that you intend "resource acquisition is initialization" to be applied only for the current scope, and have no intent to transfer
ownership.</p>
<p>A secondary reason to use <b> scoped_ptr</b> is to prevent a later maintenance programmer from adding a function that actually transfers
ownership by returning the <b> auto_ptr</b> (because the maintenance programmer saw
<b>auto_ptr</b>, and assumed ownership could safely be transferred.)&nbsp;</p>
<p>Think of <b>bool</b> vs <b>int</b>. We all know that under the covers <b> bool</b> is usually
just an <b>int</b>. Indeed, some argued against including <b> bool</b> in the
C++ standard because of that. But by coding <b> bool</b> rather than <b> int</b>, you tell your readers
what your intent is. Same with <b> scoped_ptr</b> - you are signaling intent.</p>
<p>It has been suggested that <b>boost::scoped_ptr&lt;T&gt;</b> is equivalent to
<b>std::auto_ptr&lt;T> const</b>.&nbsp; Ed Brey pointed out, however, that
reset() will not work on a <b>std::auto_ptr&lt;T> const.</b></p>
<h2><a name="Handle/Body">Handle/Body</a> Idiom</h2>
<p>One common usage of <b>scoped_ptr</b> is to implement a handle/body (also
called pimpl) idiom which avoids exposing the body (implementation) in the header
file.</p>
<p>The <a href="scoped_ptr_example_test.cpp">scoped_ptr_example_test.cpp</a>
sample program includes a header file, <a href="scoped_ptr_example.hpp">scoped_ptr_example.hpp</a>,
which uses a <b>scoped_ptr&lt;&gt;</b> to an incomplete type to hide the
implementation.&nbsp;&nbsp; The
instantiation of member functions which require a complete type occurs in the <a href="scoped_ptr_example.cpp">scoped_ptr_example.cpp</a>
implementation file.</p>
<h2>FAQ</h2>
<p><b>Q</b>. Why doesn't <b>scoped_ptr</b> have a release() member?<br>
<b>A</b>. Because the whole point of <b>scoped_ptr</b> is to signal intent not
to transfer ownership.&nbsp; Use <b>std::auto_ptr</b> if ownership transfer is
required.</p>
<hr>
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B %Y" startspan -->24 May 2001<!--webbot bot="Timestamp" endspan i-checksum="15110" --></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>

16
scoped_ptr_example.cpp Normal file
View File

@ -0,0 +1,16 @@
// Boost scoped_ptr_example implementation file -----------------------------//
#include "scoped_ptr_example.hpp"
#include <iostream>
class example::implementation
{
public:
~implementation() { std::cout << "destroying implementation\n"; }
};
example::example() : _imp( new implementation ) {}
void example::do_something() { std::cout << "did something\n"; }
example::~example() {}

21
scoped_ptr_example.hpp Normal file
View File

@ -0,0 +1,21 @@
// Boost scoped_ptr_example header file ------------------------------------//
#include <boost/smart_ptr.hpp>
// The point of this example is to prove that even though
// example::implementation is an incomplete type in translation units using
// this header, scoped_ptr< implementation > is still valid because the type
// is complete where it counts - in the inplementation translation unit where
// destruction is actually instantiated.
class example : boost::noncopyable
{
public:
example();
~example();
void do_something();
private:
class implementation;
boost::scoped_ptr< implementation > _imp; // hide implementation details
};

View File

@ -0,0 +1,10 @@
// Boost scoped_ptr_example_test main program -------------------------------//
#include "scoped_ptr_example.hpp"
int main()
{
example my_example;
my_example.do_something();
return 0;
}

189
shared_array.htm Normal file
View File

@ -0,0 +1,189 @@
<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_ptr</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 C++ Standard Library <strong>vector</strong> is <strong> </strong>a <strong>
</strong>heavier duty alternative to a <strong>shared_array</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;<a href="../../boost/smart_ptr.hpp">boost/smart_ptr.hpp</a>&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><b>T</b> is not required be a complete type.&nbsp;
See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p>
<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><b>T</b> is not required be a complete type.&nbsp;
See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</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><b>T</b> is not required be a complete type.&nbsp;
See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</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><b>T</b> is not required be a complete type.&nbsp;
See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</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 <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->24 May, 2001<!--webbot bot="Timestamp" endspan i-checksum="13964" -->
</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>

269
shared_ptr.htm Normal file
View File

@ -0,0 +1,269 @@
<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><a href="#Introduction">Introduction<br>
Synopsis</a><br>
<a href="#Members">Members</a><br>
<a href="#shared_ptr_example">Example</a><br>
<a href="#Handle/Body">Handle/Body Idiom</a><br>
<a href="smarttests.htm">Frequently Asked Questions<br>
Smart Pointer Timings</a></p>
<h2><a name="Introduction">Introduction</a></h2>
<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 <a name="Synopsis"> Synopsis</a></h2>
<pre>#include &lt;<a href="../../boost/smart_ptr.hpp">boost/smart_ptr.hpp</a>&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 <a name="Members"> Members</a></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><b>T</b> is not required by get() to be a complete type .&nbsp; See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p>
<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><b>T</b> is not required be a complete type.&nbsp;
See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</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><b>T</b> is not required be a complete type.&nbsp;
See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</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><b>T</b> is not required be a complete type.&nbsp;
See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</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>See <a href="shared_ptr_example.cpp"> shared_ptr_example.cpp</a> for a complete example program.</p>
<p>This program builds a std::vector and std::set of FooPtr's.</p>
<p>Note that after the two containers have been populated, some of the FooPtr objects
will have use_count()==1 rather than use_count()==2, since foo_set is a std::set
rather than a std::multiset, and thus does not contain duplicate entries.&nbsp; Furthermore, use_count() may be even higher
at various times while push_back() and insert() container operations are performed.&nbsp;
More complicated yet, the container operations may throw exceptions under a
variety of circumstances.&nbsp; Without using a smart pointer, memory and
exception management would be a nightmare.</p>
<h2><a name="Handle/Body">Handle/Body</a> Idiom</h2>
<p>One common usage of <b>shared_ptr</b> is to implement a handle/body (also
called pimpl) idiom which avoids exposing the body (implementation) in the header
file.</p>
<p>The <a href="shared_ptr_example2_test.cpp">shared_ptr_example2_test.cpp</a>
sample program includes a header file, <a href="shared_ptr_example2.hpp">shared_ptr_example2.hpp</a>,
which uses a <b>shared_ptr&lt;&gt;</b> to an incomplete type to hide the
implementation.&nbsp;&nbsp; The
instantiation of member functions which require a complete type occurs in the <a href="shared_ptr_example2.cpp">shared_ptr_example2.cpp</a>
implementation file.</p>
<h2><a name="FAQ">Frequently Asked Questions</a></h2>
<p><b>Q.</b> Why doesn't <b>shared_ptr</b> have template parameters supplying
traits or policies to allow extensive user customization?<br>
<b>A.</b> Parameterization discourages users.&nbsp; <b>Shared_ptr</b> is
carefully crafted to meet common needs without extensive parameterization.
Someday a highly configurable smart pointer may be invented that is also very
easy to use and very hard to misuse.&nbsp; Until then, <b>shared_ptr</b> is the
smart pointer of choice for a wide range of applications.&nbsp; (Those
interested in policy based smart pointers should read <a href="http://cseng.aw.com/book/0,,0201704315,00.html">Modern
C++ Design</a> by Andrei Alexandrescu.)</p>
<p><b>Q.</b> Why doesn't <b>shared_ptr</b> use a linked list implementation?<br>
<b>A.</b> A linked list implementation does not offer enough advantages to
offset the added cost of an extra pointer.&nbsp; See <a href="smarttests.htm">timings</a>
page.</p>
<p><b>Q.</b> Why don't <b>shared_ptr</b> (and the other Boost smart pointers)
supply an automatic conversion to <b>T*</b>?<br>
<b>A.</b> Automatic conversion is believed to be too error prone.</p>
<p><b>Q.</b> Why does <b>shared_ptr</b> supply use_count()?<br>
<b>A.</b> As an aid to writing test cases and debugging displays. One of the
progenitors had use_count(), and it was useful in tracking down bugs in a
complex project that turned out to have cyclic-dependencies.</p>
<p><b>Q.</b> Why doesn't <b>shared_ptr</b> specify complexity requirements?<br>
<b>A.</b> Because complexity limit implementors and complicate the specification without apparent benefit to
<b>shared_ptr</b> users. For example, error-checking implementations might become non-conforming if they
had to meet stringent complexity requirements.</p>
<p><b>Q.</b> Why doesn't <b>shared_ptr</b> provide (your pet feature here)?<br>
<b>A.</b> Because (your pet feature here) would mandate a reference counted (or a link-list, or ...) implementation. This is not the intent.
[Provided by Peter Dimov]<br>
</p>
<hr>
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->13 July, 2001<!--webbot bot="Timestamp" endspan i-checksum="21067" -->
</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>

96
shared_ptr_example.cpp Normal file
View File

@ -0,0 +1,96 @@
// Boost shared_ptr_example.cpp --------------------------------------------//
// (C) Copyright Beman Dawes 2001. Permission to copy,
// use, modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided "as is"
// without express or implied warranty, and with no claim as to its
// suitability for any purpose.
// See http://www.boost.org for most recent version including documentation.
// Revision History
// 21 May 01 Initial complete version (Beman Dawes)
// The original code for this example appeared in the shared_ptr documentation.
// Ray Gallimore pointed out that foo_set was missing a Compare template
// argument, so would not work as intended. At that point the code was
// turned into an actual .cpp file so it could be compiled and tested.
#include <vector>
#include <set>
#include <iostream>
#include <algorithm>
#include <boost/smart_ptr.hpp>
// The application will produce a series of
// objects of type Foo which later must be
// accessed both by occurrence (std::vector)
// and by ordering relationship (std::set).
struct Foo
{
Foo( int _x ) : x(_x) {}
~Foo() { std::cout << "Destructing a Foo with x=" << x << "\n"; }
int x;
/* ... */
};
typedef boost::shared_ptr<Foo> FooPtr;
struct FooPtrOps
{
bool operator()( const FooPtr & a, const FooPtr & b )
{ return a->x > b->x; }
void operator()( const FooPtr & a )
{ std::cout << a->x << "\n"; }
};
int main()
{
std::vector<FooPtr> foo_vector;
std::set<FooPtr,FooPtrOps> foo_set; // NOT multiset!
FooPtr foo_ptr( new Foo( 2 ) );
foo_vector.push_back( foo_ptr );
foo_set.insert( foo_ptr );
foo_ptr.reset( new Foo( 1 ) );
foo_vector.push_back( foo_ptr );
foo_set.insert( foo_ptr );
foo_ptr.reset( new Foo( 3 ) );
foo_vector.push_back( foo_ptr );
foo_set.insert( foo_ptr );
foo_ptr.reset ( new Foo( 2 ) );
foo_vector.push_back( foo_ptr );
foo_set.insert( foo_ptr );
std::cout << "foo_vector:\n";
std::for_each( foo_vector.begin(), foo_vector.end(), FooPtrOps() );
std::cout << "\nfoo_set:\n";
std::for_each( foo_set.begin(), foo_set.end(), FooPtrOps() );
std::cout << "\n";
// Expected output:
//
// foo_vector:
// 2
// 1
// 3
// 2
//
// foo_set:
// 3
// 2
// 1
//
// Destructing a Foo with x=2
// Destructing a Foo with x=1
// Destructing a Foo with x=3
// Destructing a Foo with x=2
return 0;
}

21
shared_ptr_example2.cpp Normal file
View File

@ -0,0 +1,21 @@
// Boost shared_ptr_example2 implementation file -----------------------------//
#include "shared_ptr_example2.hpp"
#include <iostream>
class example::implementation
{
public:
~implementation() { std::cout << "destroying implementation\n"; }
};
example::example() : _imp( new implementation ) {}
example::example( const example & s ) : _imp( s._imp ) {}
example & example::operator=( const example & s )
{ _imp = s._imp; return *this; }
void example::do_something()
{ std::cout << "use_count() is " << _imp.use_count() << "\n"; }
example::~example() {}

27
shared_ptr_example2.hpp Normal file
View File

@ -0,0 +1,27 @@
// Boost shared_ptr_example2 header file -----------------------------------//
#include <boost/smart_ptr.hpp>
// This example demonstrates the handle/body idiom (also called pimpl and
// several other names). It separates the interface (in this header file)
// from the implementation (in shared_ptr_example2.cpp).
// Note that even though example::implementation is an incomplete type in
// some translation units using this header, shared_ptr< implementation >
// is still valid because the type is complete where it counts - in the
// shared_ptr_example2.cpp translation unit where functions requiring a
// complete type are actually instantiated.
class example
{
public:
example();
~example();
example( const example & );
example & operator=( const example & );
void do_something();
private:
class implementation;
boost::shared_ptr< implementation > _imp; // hide implementation details
};

View File

@ -0,0 +1,15 @@
// Boost shared_ptr_example2_test main program ------------------------------//
#include "shared_ptr_example2.hpp"
int main()
{
example a;
a.do_something();
example b(a);
b.do_something();
example c;
c = a;
c.do_something();
return 0;
}

155
smart_ptr.htm Normal file
View File

@ -0,0 +1,155 @@
<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. Noncopyable.</td>
</tr>
<tr>
<td><a href="scoped_array.htm"><strong>scoped_array</strong></a></td>
<td>Simple sole ownership of arrays. Noncopyable.</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><b>T</b></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><b>T</b></tt> throw exceptions.</p>
<p><code><b>T</b></code> may be an incomplete type at the point of smart pointer
declaration.&nbsp; Unless otherwise specified, it is required that <code><b>T</b></code>
be a complete type at points of smart pointer instantiation. Implementations are
required to diagnose (treat as an error) all violations of this requirement,
including deletion of an incomplete type. See <a href="../utility/utility.htm#checked_delete">checked_delete()</a>.</p>
<h3>Rationale</h3>
<p>The requirements on <tt><b>T</b></tt> are carefully crafted to maximize safety
yet allow handle-body (also called pimpl) and similar idioms.&nbsp; In these idioms a
smart pointer may appear in translation units where <tt><b>T</b></tt> is an
incomplete type.&nbsp; This separates interface from implementation and hides
implementation from translation units which merely use the interface.&nbsp;
Examples described in the documentation for specific smart pointers illustrate
use of smart pointers in these idioms.</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>May, 2001. Vladimir Prus suggested requiring a complete type on
destruction.&nbsp; Refinement evolved in discussions including Dave Abrahams,
Greg Colvin, Beman Dawes, Rainer Deyke, Peter Dimov, John Maddock, Vladimir Prus,
Shankar Sai, and others.</p>
<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 May 2001<!--webbot bot="Timestamp" endspan i-checksum="15110"
--></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>

289
smart_ptr_test.cpp Normal file
View File

@ -0,0 +1,289 @@
// smart pointer test program ----------------------------------------------//
// (C) Copyright Beman Dawes 1998, 1999. Permission to copy, use, modify, sell
// and distribute this software is granted provided this copyright notice
// appears in all copies. This software is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
// Revision History
// 24 May 01 use Boost test library for error detection, reporting, add tests
// for operations on incomplete types (Beman Dawes)
// 29 Nov 99 added std::swap and associative container tests (Darin Adler)
// 25 Sep 99 added swap tests
// 20 Jul 99 header name changed to .hpp
// 20 Apr 99 additional error tests added.
#define BOOST_INCLUDE_MAIN
#include <boost/test/test_tools.hpp>
#include <boost/smart_ptr.hpp>
#include <cstring>
#include <iostream>
#include <set>
class Incomplete;
Incomplete * get_ptr( boost::shared_ptr<Incomplete>& incomplete )
{
return incomplete.get();
}
using namespace std;
using boost::scoped_ptr;
using boost::scoped_array;
using boost::shared_ptr;
using boost::shared_array;
template<typename T>
void ck( const T* v1, T v2 ) { BOOST_TEST( *v1 == v2 ); }
namespace {
int UDT_use_count; // independent of pointer maintained counts
}
// user defined type -------------------------------------------------------//
class UDT {
long value_;
public:
explicit UDT( long value=0 ) : value_(value) { ++UDT_use_count; }
~UDT() {
--UDT_use_count;
cout << "UDT with value " << value_ << " being destroyed" << endl;
}
long value() const { return value_; }
void value( long v ) { value_ = v;; }
}; // UDT
// tests on incomplete types -----------------------------------------------//
// Certain smart pointer operations are specified to work on incomplete types,
// and some uses depend upon this feature. These tests verify compilation
// only - the functions aren't actually invoked.
class Incomplete;
Incomplete * check_incomplete( scoped_ptr<Incomplete>& incomplete )
{
return incomplete.get();
}
Incomplete * check_incomplete( shared_ptr<Incomplete>& incomplete,
shared_ptr<Incomplete>& i2 )
{
incomplete.swap(i2);
cout << incomplete.use_count() << " " << incomplete.unique() << endl;
return incomplete.get();
}
// main --------------------------------------------------------------------//
// This isn't a very systematic test; it just hits some of the basics.
int test_main( int, char ** ) {
BOOST_TEST( UDT_use_count == 0 ); // reality check
// test scoped_ptr with a built-in type
long * lp = new long;
scoped_ptr<long> sp ( lp );
BOOST_TEST( sp.get() == lp );
BOOST_TEST( lp == sp.get() );
BOOST_TEST( &*sp == lp );
*sp = 1234568901L;
BOOST_TEST( *sp == 1234568901L );
BOOST_TEST( *lp == 1234568901L );
ck( static_cast<long*>(sp.get()), 1234568901L );
ck( lp, *sp );
sp.reset();
BOOST_TEST( sp.get() == 0 );
// test scoped_ptr with a user defined type
scoped_ptr<UDT> udt_sp ( new UDT( 999888777 ) );
BOOST_TEST( udt_sp->value() == 999888777 );
udt_sp.reset();
udt_sp.reset( new UDT( 111222333 ) );
BOOST_TEST( udt_sp->value() == 111222333 );
udt_sp.reset( new UDT( 333222111 ) );
BOOST_TEST( udt_sp->value() == 333222111 );
// test scoped_array with a build-in type
char * sap = new char [ 100 ];
scoped_array<char> sa ( sap );
BOOST_TEST( sa.get() == sap );
BOOST_TEST( sap == sa.get() );
strcpy( sa.get(), "Hot Dog with mustard and relish" );
BOOST_TEST( strcmp( sa.get(), "Hot Dog with mustard and relish" ) == 0 );
BOOST_TEST( strcmp( sap, "Hot Dog with mustard and relish" ) == 0 );
BOOST_TEST( sa[0] == 'H' );
BOOST_TEST( sa[30] == 'h' );
sa[0] = 'N';
sa[4] = 'd';
BOOST_TEST( strcmp( sap, "Not dog with mustard and relish" ) == 0 );
sa.reset();
BOOST_TEST( sa.get() == 0 );
// test shared_ptr with a built-in type
int * ip = new int;
shared_ptr<int> cp ( ip );
BOOST_TEST( ip == cp.get() );
BOOST_TEST( cp.use_count() == 1 );
*cp = 54321;
BOOST_TEST( *cp == 54321 );
BOOST_TEST( *ip == 54321 );
ck( static_cast<int*>(cp.get()), 54321 );
ck( static_cast<int*>(ip), *cp );
shared_ptr<int> cp2 ( cp );
BOOST_TEST( ip == cp2.get() );
BOOST_TEST( cp.use_count() == 2 );
BOOST_TEST( cp2.use_count() == 2 );
BOOST_TEST( *cp == 54321 );
BOOST_TEST( *cp2 == 54321 );
ck( static_cast<int*>(cp2.get()), 54321 );
ck( static_cast<int*>(ip), *cp2 );
shared_ptr<int> cp3 ( cp );
BOOST_TEST( cp.use_count() == 3 );
BOOST_TEST( cp2.use_count() == 3 );
BOOST_TEST( cp3.use_count() == 3 );
cp.reset();
BOOST_TEST( cp2.use_count() == 2 );
BOOST_TEST( cp3.use_count() == 2 );
BOOST_TEST( cp.use_count() == 1 );
cp.reset( new int );
*cp = 98765;
BOOST_TEST( *cp == 98765 );
*cp3 = 87654;
BOOST_TEST( *cp3 == 87654 );
BOOST_TEST( *cp2 == 87654 );
cp.swap( cp3 );
BOOST_TEST( *cp == 87654 );
BOOST_TEST( *cp2 == 87654 );
BOOST_TEST( *cp3 == 98765 );
cp.swap( cp3 );
BOOST_TEST( *cp == 98765 );
BOOST_TEST( *cp2 == 87654 );
BOOST_TEST( *cp3 == 87654 );
cp2 = cp2;
BOOST_TEST( cp2.use_count() == 2 );
BOOST_TEST( *cp2 == 87654 );
cp = cp2;
BOOST_TEST( cp2.use_count() == 3 );
BOOST_TEST( *cp2 == 87654 );
BOOST_TEST( cp.use_count() == 3 );
BOOST_TEST( *cp == 87654 );
shared_ptr<int> cp4;
swap( cp2, cp4 );
BOOST_TEST( cp4.use_count() == 3 );
BOOST_TEST( *cp4 == 87654 );
BOOST_TEST( cp2.get() == 0 );
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
set< shared_ptr<int> > scp;
scp.insert(cp4);
BOOST_TEST( scp.find(cp4) != scp.end() );
BOOST_TEST( scp.find(cp4) == scp.find( shared_ptr<int>(cp4) ) );
#endif
// test shared_array with a built-in type
char * cap = new char [ 100 ];
shared_array<char> ca ( cap );
BOOST_TEST( ca.get() == cap );
BOOST_TEST( cap == ca.get() );
BOOST_TEST( &ca[0] == cap );
strcpy( ca.get(), "Hot Dog with mustard and relish" );
BOOST_TEST( strcmp( ca.get(), "Hot Dog with mustard and relish" ) == 0 );
BOOST_TEST( strcmp( cap, "Hot Dog with mustard and relish" ) == 0 );
BOOST_TEST( ca[0] == 'H' );
BOOST_TEST( ca[30] == 'h' );
shared_array<char> ca2 ( ca );
shared_array<char> ca3 ( ca2 );
ca[0] = 'N';
ca[4] = 'd';
BOOST_TEST( strcmp( ca.get(), "Not dog with mustard and relish" ) == 0 );
BOOST_TEST( strcmp( ca2.get(), "Not dog with mustard and relish" ) == 0 );
BOOST_TEST( strcmp( ca3.get(), "Not dog with mustard and relish" ) == 0 );
BOOST_TEST( ca.use_count() == 3 );
BOOST_TEST( ca2.use_count() == 3 );
BOOST_TEST( ca3.use_count() == 3 );
ca2.reset();
BOOST_TEST( ca.use_count() == 2 );
BOOST_TEST( ca3.use_count() == 2 );
BOOST_TEST( ca2.use_count() == 1 );
ca.reset();
BOOST_TEST( ca.get() == 0 );
shared_array<char> ca4;
swap( ca3, ca4 );
BOOST_TEST( ca4.use_count() == 1 );
BOOST_TEST( strcmp( ca4.get(), "Not dog with mustard and relish" ) == 0 );
BOOST_TEST( ca3.get() == 0 );
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
set< shared_array<char> > sca;
sca.insert(ca4);
BOOST_TEST( sca.find(ca4) != sca.end() );
BOOST_TEST( sca.find(ca4) == sca.find( shared_array<char>(ca4) ) );
#endif
// test shared_array with user defined type
shared_array<UDT> udta ( new UDT[3] );
udta[0].value( 111 );
udta[1].value( 222 );
udta[2].value( 333 );
shared_array<UDT> udta2 ( udta );
BOOST_TEST( udta[0].value() == 111 );
BOOST_TEST( udta[1].value() == 222 );
BOOST_TEST( udta[2].value() == 333 );
BOOST_TEST( udta2[0].value() == 111 );
BOOST_TEST( udta2[1].value() == 222 );
BOOST_TEST( udta2[2].value() == 333 );
udta2.reset();
BOOST_TEST( udta2.get() == 0 );
BOOST_TEST( udta.use_count() == 1 );
BOOST_TEST( udta2.use_count() == 1 );
BOOST_TEST( UDT_use_count == 4 ); // reality check
// test shared_ptr with a user defined type
UDT * up = new UDT;
shared_ptr<UDT> sup ( up );
BOOST_TEST( up == sup.get() );
BOOST_TEST( sup.use_count() == 1 );
sup->value( 54321 ) ;
BOOST_TEST( sup->value() == 54321 );
BOOST_TEST( up->value() == 54321 );
shared_ptr<UDT> sup2;
sup2 = sup;
BOOST_TEST( sup2->value() == 54321 );
BOOST_TEST( sup.use_count() == 2 );
BOOST_TEST( sup2.use_count() == 2 );
sup2 = sup2;
BOOST_TEST( sup2->value() == 54321 );
BOOST_TEST( sup.use_count() == 2 );
BOOST_TEST( sup2.use_count() == 2 );
cout << "OK" << endl;
new char[12345]; // deliberate memory leak to verify leaks detected
return 0;
} // main

BIN
smarttest.zip Normal file

Binary file not shown.

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 -->17 Aug 2001<!--webbot bot="Timestamp" endspan i-checksum="14763" -->
</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>