forked from boostorg/smart_ptr
This commit was manufactured by cvs2svn to create branch 'RC_1_28_0'.
[SVN r13795]
This commit is contained in:
105
compatibility.htm
Normal file
105
compatibility.htm
Normal file
@@ -0,0 +1,105 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>Smart Pointer Changes</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="middle" width="277" height="86">Smart
|
||||
Pointer Changes</h1>
|
||||
|
||||
<p>The February 2002 change to the Boost smart pointers introduced a number
|
||||
of changes. Since the previous version of the smart pointers was in use for
|
||||
a long time, it's useful to have a detailed list of what changed from a library
|
||||
user's point of view.</p>
|
||||
|
||||
<p>Note that for compilers that don't support member templates well enough,
|
||||
a separate implementation is used that lacks many of the new features and is
|
||||
more like the old version.</p>
|
||||
|
||||
<h2>Features Requiring Code Changes to Take Advantage</h2>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>The smart pointer class templates now each have their own header file.
|
||||
For compatibility, the
|
||||
<a href="../../boost/smart_ptr.hpp"><boost/smart_ptr.hpp></a>
|
||||
header now includes the headers for the four classic smart pointer class templates.</li>
|
||||
|
||||
<li>The <b>weak_ptr</b> template was added.</li>
|
||||
|
||||
<li>The new <b>shared_ptr</b> and <b>shared_array</b> relax the requirement that the pointed-to object's
|
||||
destructor must be visible when instantiating the <b>shared_ptr</b> destructor.
|
||||
This makes it easier to have shared_ptr members in classes without explicit destructors.</li>
|
||||
|
||||
<li>A custom deallocator can be passed in when creating a <b>shared_ptr</b> or <b>shared_array</b>.</li>
|
||||
|
||||
<li><b>shared_static_cast</b> and <b>shared_dynamic_cast</b> function templates are
|
||||
provided which work for <b>shared_ptr</b> and <b>weak_ptr</b> as <b>static_cast</b> and
|
||||
<b>dynamic_cast</b> do for pointers.</li>
|
||||
|
||||
<li>The self-assignment misfeature has been removed from <b>shared_ptr::reset</b>,
|
||||
although it is still present in <b>scoped_ptr</b>, and in <b>std::auto_ptr</b>.
|
||||
Calling <b>reset</b> with a pointer to the object that's already owned by the
|
||||
<b>shared_ptr</b> results in undefined behavior
|
||||
(an assertion, or eventually a double-delete if assertions are off).</li>
|
||||
|
||||
<li>The <b>BOOST_SMART_PTR_CONVERSION</b> feature has been removed.</li>
|
||||
|
||||
<li><b>shared_ptr<void></b> is now allowed.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h2>Features That Improve Robustness</h2>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>The manipulation of use counts is now <a name="threadsafe">thread safe</a> on Windows, Linux, and platforms
|
||||
that support pthreads. See the
|
||||
<a href="../../boost/detail/atomic_count.hpp"><boost/detail/atomic_count.hpp></a>
|
||||
file for details</li>
|
||||
|
||||
<li>The new shared_ptr will always delete the object using the pointer it was originally constructed with.
|
||||
This prevents subtle problems that could happen if the last <b>shared_ptr</b> was a pointer to a sub-object
|
||||
of a class that did not have a virtual destructor.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h2>Implementation Details</h2>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>Some bugs in the assignment operator implementations and in <b>reset</b>
|
||||
have been fixed by using the "copy and swap" idiom.</li>
|
||||
|
||||
<li>Assertions have been added to check preconditions of various functions;
|
||||
however, since these use the new
|
||||
<a href="../../boost/assert.hpp"><boost/assert.hpp></a>
|
||||
header, the assertions are disabled by default.</li>
|
||||
|
||||
<li>The partial specialization of <b>std::less</b> has been replaced by <b>operator<</b>
|
||||
overloads which accomplish the same thing without relying on undefined behavior.</li>
|
||||
|
||||
<li>The incorrect overload of <b>std::swap</b> has been replaced by <b>boost::swap</b>, which
|
||||
has many of the same advantages for generic programming but does not violate the C++ standard.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised 1 February 2002</p>
|
||||
|
||||
<p>Copyright 2002 Darin Adler.
|
||||
Permission to copy, use,
|
||||
modify, sell and distribute this document is granted provided this copyright
|
||||
notice appears in all copies. This document is provided "as is"
|
||||
without express or implied warranty, and with no claim as to its suitability for
|
||||
any purpose.</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
BIN
gccspeed.gif
Normal file
BIN
gccspeed.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
121
include/boost/detail/atomic_count.hpp
Normal file
121
include/boost/detail/atomic_count.hpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#ifndef BOOST_DETAIL_ATOMIC_COUNT_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_ATOMIC_COUNT_HPP_INCLUDED
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost/detail/atomic_count.hpp - thread/SMP safe reference counter
|
||||
//
|
||||
// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// typedef <implementation-defined> boost::detail::atomic_count;
|
||||
//
|
||||
// atomic_count a(n);
|
||||
//
|
||||
// (n is convertible to long)
|
||||
//
|
||||
// Effects: Constructs an atomic_count with an initial value of n
|
||||
//
|
||||
// a;
|
||||
//
|
||||
// Returns: (long) the current value of a
|
||||
//
|
||||
// ++a;
|
||||
//
|
||||
// Effects: Atomically increments the value of a
|
||||
// Returns: nothing
|
||||
//
|
||||
// --a;
|
||||
//
|
||||
// Effects: Atomically decrements the value of a
|
||||
// Returns: (long) zero if the new value of a is zero,
|
||||
// unspecified non-zero value otherwise (usually the new value)
|
||||
//
|
||||
// Important note: when --a returns zero, it must act as a
|
||||
// read memory barrier (RMB); i.e. the calling thread must
|
||||
// have a synchronized view of the memory
|
||||
//
|
||||
// On Intel IA-32 (x86) memory is always synchronized, so this
|
||||
// is not a problem.
|
||||
//
|
||||
// On many architectures the atomic instructions already act as
|
||||
// a memory barrier.
|
||||
//
|
||||
// This property is necessary for proper reference counting, since
|
||||
// a thread can update the contents of a shared object, then
|
||||
// release its reference, and another thread may immediately
|
||||
// release the last reference causing object destruction.
|
||||
//
|
||||
// The destructor needs to have a synchronized view of the
|
||||
// object to perform proper cleanup.
|
||||
//
|
||||
// Original example by Alexander Terekhov:
|
||||
//
|
||||
// Given:
|
||||
//
|
||||
// - a mutable shared object OBJ;
|
||||
// - two threads THREAD1 and THREAD2 each holding
|
||||
// a private smart_ptr object pointing to that OBJ.
|
||||
//
|
||||
// t1: THREAD1 updates OBJ (thread-safe via some synchronization)
|
||||
// and a few cycles later (after "unlock") destroys smart_ptr;
|
||||
//
|
||||
// t2: THREAD2 destroys smart_ptr WITHOUT doing any synchronization
|
||||
// with respect to shared mutable object OBJ; OBJ destructors
|
||||
// are called driven by smart_ptr interface...
|
||||
//
|
||||
|
||||
// Note: atomic_count_linux.hpp has been disabled by default; see the
|
||||
// comments inside for more info.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
typedef long atomic_count;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#elif defined(BOOST_USE_ASM_ATOMIC_H)
|
||||
# include <boost/detail/atomic_count_linux.hpp>
|
||||
#elif defined(BOOST_AC_USE_PTHREADS)
|
||||
# include <boost/detail/atomic_count_pthreads.hpp>
|
||||
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
||||
# include <boost/detail/atomic_count_win32.hpp>
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# define BOOST_AC_USE_PTHREADS
|
||||
# include <boost/detail/atomic_count_pthreads.hpp>
|
||||
#else
|
||||
|
||||
// #warning Unrecognized platform, detail::atomic_count will not be thread safe
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
typedef long atomic_count;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_ATOMIC_COUNT_HPP_INCLUDED
|
70
include/boost/detail/atomic_count_linux.hpp
Normal file
70
include/boost/detail/atomic_count_linux.hpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef BOOST_DETAIL_ATOMIC_COUNT_LINUX_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_ATOMIC_COUNT_LINUX_HPP_INCLUDED
|
||||
|
||||
//
|
||||
// boost/detail/atomic_count_linux.hpp
|
||||
//
|
||||
// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
//
|
||||
// This implementation uses <asm/atomic.h>. This is a kernel header;
|
||||
// using kernel headers in a user program may cause a number of problems,
|
||||
// and not all flavors of Linux provide the atomic instructions.
|
||||
//
|
||||
// This file is only provided because the performance of this implementation
|
||||
// is significantly higher than the pthreads version. Use at your own risk
|
||||
// (by defining BOOST_USE_ASM_ATOMIC_H.)
|
||||
//
|
||||
|
||||
#include <asm/atomic.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class atomic_count
|
||||
{
|
||||
public:
|
||||
|
||||
explicit atomic_count(long v)
|
||||
{
|
||||
atomic_t init = ATOMIC_INIT(v);
|
||||
value_ = init;
|
||||
}
|
||||
|
||||
void operator++()
|
||||
{
|
||||
atomic_inc(&value_);
|
||||
}
|
||||
|
||||
long operator--()
|
||||
{
|
||||
return !atomic_dec_and_test(&value_);
|
||||
}
|
||||
|
||||
operator long() const
|
||||
{
|
||||
return atomic_read(&value_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
atomic_count(atomic_count const &);
|
||||
atomic_count & operator=(atomic_count const &);
|
||||
|
||||
atomic_t value_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_ATOMIC_COUNT_LINUX_HPP_INCLUDED
|
97
include/boost/detail/atomic_count_pthreads.hpp
Normal file
97
include/boost/detail/atomic_count_pthreads.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#ifndef BOOST_DETAIL_ATOMIC_COUNT_PTHREADS_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_ATOMIC_COUNT_PTHREADS_HPP_INCLUDED
|
||||
|
||||
//
|
||||
// boost/detail/atomic_count_pthreads.hpp
|
||||
//
|
||||
// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
//
|
||||
// The generic pthread_mutex-based implementation sometimes leads to
|
||||
// inefficiencies. Example: a class with two atomic_count members
|
||||
// can get away with a single mutex.
|
||||
//
|
||||
// Users can detect this situation by checking BOOST_AC_USE_PTHREADS.
|
||||
//
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class atomic_count
|
||||
{
|
||||
private:
|
||||
|
||||
class scoped_lock
|
||||
{
|
||||
public:
|
||||
|
||||
scoped_lock(pthread_mutex_t & m): m_(m)
|
||||
{
|
||||
pthread_mutex_lock(&m_);
|
||||
}
|
||||
|
||||
~scoped_lock()
|
||||
{
|
||||
pthread_mutex_unlock(&m_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
pthread_mutex_t & m_;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
explicit atomic_count(long v): value_(v)
|
||||
{
|
||||
pthread_mutex_init(&mutex_, 0);
|
||||
}
|
||||
|
||||
~atomic_count()
|
||||
{
|
||||
pthread_mutex_destroy(&mutex_);
|
||||
}
|
||||
|
||||
void operator++()
|
||||
{
|
||||
scoped_lock lock(mutex_);
|
||||
++value_;
|
||||
}
|
||||
|
||||
long operator--()
|
||||
{
|
||||
scoped_lock lock(mutex_);
|
||||
return --value_;
|
||||
}
|
||||
|
||||
operator long() const
|
||||
{
|
||||
scoped_lock lock(mutex_);
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
atomic_count(atomic_count const &);
|
||||
atomic_count & operator=(atomic_count const &);
|
||||
|
||||
mutable pthread_mutex_t mutex_;
|
||||
long value_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_ATOMIC_COUNT_PTHREADS_HPP_INCLUDED
|
62
include/boost/detail/atomic_count_win32.hpp
Normal file
62
include/boost/detail/atomic_count_win32.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef BOOST_DETAIL_ATOMIC_COUNT_WIN32_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_ATOMIC_COUNT_WIN32_HPP_INCLUDED
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost/detail/atomic_count_win32.hpp
|
||||
//
|
||||
// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include <boost/detail/winapi.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class atomic_count
|
||||
{
|
||||
public:
|
||||
|
||||
explicit atomic_count(long v): value_(v)
|
||||
{
|
||||
}
|
||||
|
||||
long operator++()
|
||||
{
|
||||
return winapi::InterlockedIncrement(&value_);
|
||||
}
|
||||
|
||||
long operator--()
|
||||
{
|
||||
return winapi::InterlockedDecrement(&value_);
|
||||
}
|
||||
|
||||
operator long() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
atomic_count(atomic_count const &);
|
||||
atomic_count & operator=(atomic_count const &);
|
||||
|
||||
volatile long value_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_ATOMIC_COUNT_WIN32_HPP_INCLUDED
|
67
include/boost/detail/lightweight_mutex.hpp
Normal file
67
include/boost/detail/lightweight_mutex.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef BOOST_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost/detail/lightweight_mutex.hpp - lightweight mutex
|
||||
//
|
||||
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// typedef <implementation-defined> boost::detail::lightweight_mutex;
|
||||
//
|
||||
// boost::detail::lightweight_mutex meets the Mutex concept requirements
|
||||
// See http://www.boost.org/libs/thread/doc/mutex_concept.html#Mutex
|
||||
//
|
||||
// * Used by the smart pointer library
|
||||
// * Performance oriented
|
||||
// * Header-only implementation
|
||||
// * Small memory footprint
|
||||
// * Not a general purpose mutex, use boost::mutex, CRITICAL_SECTION or
|
||||
// pthread_mutex instead.
|
||||
// * Never spin in a tight lock/do-something/unlock loop, since
|
||||
// lightweight_mutex does not guarantee fairness.
|
||||
// * Never keep a lightweight_mutex locked for long periods.
|
||||
//
|
||||
|
||||
// Note: lwm_linux.hpp has been disabled by default; see the comments
|
||||
// inside for more info.
|
||||
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
//
|
||||
// Note to implementors: if you write a platform-specific lightweight_mutex
|
||||
// for a platform that supports pthreads, be sure to test its performance
|
||||
// against the pthreads-based version using smart_ptr_timing_test.cpp and
|
||||
// smart_ptr_mt_test.cpp. Custom versions are usually not worth the trouble
|
||||
// _unless_ the performance gains are substantial.
|
||||
//
|
||||
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
# include <boost/detail/lwm_nop.hpp>
|
||||
#elif defined(BOOST_USE_ASM_ATOMIC_H)
|
||||
# include <boost/detail/lwm_linux.hpp>
|
||||
#elif defined(BOOST_LWM_USE_CRITICAL_SECTION)
|
||||
# include <boost/detail/lwm_win32_cs.hpp>
|
||||
#elif defined(BOOST_LWM_USE_PTHREADS)
|
||||
# include <boost/detail/lwm_pthreads.hpp>
|
||||
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
||||
# include <boost/detail/lwm_win32.hpp>
|
||||
#elif defined(__sgi)
|
||||
# include <boost/detail/lwm_irix.hpp>
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# define BOOST_LWM_USE_PTHREADS
|
||||
# include <boost/detail/lwm_pthreads.hpp>
|
||||
#else
|
||||
# include <boost/detail/lwm_nop.hpp>
|
||||
#endif
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED
|
78
include/boost/detail/lwm_irix.hpp
Normal file
78
include/boost/detail/lwm_irix.hpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#ifndef BOOST_DETAIL_LWM_IRIX_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_LWM_IRIX_HPP_INCLUDED
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost/detail/lwm_irix.hpp
|
||||
//
|
||||
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
|
||||
// Copyright (c) 2002 Dan Gohman
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include <sgidefs.h>
|
||||
#include <mutex.h>
|
||||
#include <sched.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class lightweight_mutex
|
||||
{
|
||||
private:
|
||||
|
||||
__uint32_t l_;
|
||||
|
||||
lightweight_mutex(lightweight_mutex const &);
|
||||
lightweight_mutex & operator=(lightweight_mutex const &);
|
||||
|
||||
public:
|
||||
|
||||
lightweight_mutex(): l_(0)
|
||||
{
|
||||
}
|
||||
|
||||
class scoped_lock;
|
||||
friend class scoped_lock;
|
||||
|
||||
class scoped_lock
|
||||
{
|
||||
private:
|
||||
|
||||
lightweight_mutex & m_;
|
||||
|
||||
scoped_lock(scoped_lock const &);
|
||||
scoped_lock & operator=(scoped_lock const &);
|
||||
|
||||
public:
|
||||
|
||||
explicit scoped_lock(lightweight_mutex & m): m_(m)
|
||||
{
|
||||
while( test_and_set32(&m_.l_, 1) )
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
~scoped_lock()
|
||||
{
|
||||
m_.l_ = 0;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_LWM_IRIX_HPP_INCLUDED
|
89
include/boost/detail/lwm_linux.hpp
Normal file
89
include/boost/detail/lwm_linux.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#ifndef BOOST_DETAIL_LWM_LINUX_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_LWM_LINUX_HPP_INCLUDED
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost/detail/lwm_linux.hpp
|
||||
//
|
||||
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
//
|
||||
// This implementation uses <asm/atomic.h>. This is a kernel header;
|
||||
// using kernel headers in a user program may cause a number of problems,
|
||||
// and not all flavors of Linux provide the atomic instructions.
|
||||
//
|
||||
// This file is only provided because the performance of this implementation
|
||||
// is about 3.5 times higher than the pthreads version. Use at your own risk
|
||||
// (by defining BOOST_USE_ASM_ATOMIC_H.)
|
||||
//
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <sched.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class lightweight_mutex
|
||||
{
|
||||
private:
|
||||
|
||||
atomic_t a_;
|
||||
|
||||
lightweight_mutex(lightweight_mutex const &);
|
||||
lightweight_mutex & operator=(lightweight_mutex const &);
|
||||
|
||||
public:
|
||||
|
||||
lightweight_mutex()
|
||||
{
|
||||
atomic_t a = ATOMIC_INIT(1);
|
||||
a_ = a;
|
||||
}
|
||||
|
||||
class scoped_lock;
|
||||
friend class scoped_lock;
|
||||
|
||||
class scoped_lock
|
||||
{
|
||||
private:
|
||||
|
||||
lightweight_mutex & m_;
|
||||
|
||||
scoped_lock(scoped_lock const &);
|
||||
scoped_lock & operator=(scoped_lock const &);
|
||||
|
||||
public:
|
||||
|
||||
explicit scoped_lock(lightweight_mutex & m): m_(m)
|
||||
{
|
||||
while( !atomic_dec_and_test(&m_.a_) )
|
||||
{
|
||||
atomic_inc(&m_.a_);
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
~scoped_lock()
|
||||
{
|
||||
atomic_inc(&m_.a_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED
|
36
include/boost/detail/lwm_nop.hpp
Normal file
36
include/boost/detail/lwm_nop.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef BOOST_DETAIL_LWM_NOP_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_LWM_NOP_HPP_INCLUDED
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost/detail/lwm_nop.hpp
|
||||
//
|
||||
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class lightweight_mutex
|
||||
{
|
||||
public:
|
||||
|
||||
typedef lightweight_mutex scoped_lock;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_LWM_NOP_HPP_INCLUDED
|
78
include/boost/detail/lwm_pthreads.hpp
Normal file
78
include/boost/detail/lwm_pthreads.hpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#ifndef BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost/detail/lwm_pthreads.hpp
|
||||
//
|
||||
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class lightweight_mutex
|
||||
{
|
||||
private:
|
||||
|
||||
pthread_mutex_t m_;
|
||||
|
||||
lightweight_mutex(lightweight_mutex const &);
|
||||
lightweight_mutex & operator=(lightweight_mutex const &);
|
||||
|
||||
public:
|
||||
|
||||
lightweight_mutex()
|
||||
{
|
||||
pthread_mutex_init(&m_, 0);
|
||||
}
|
||||
|
||||
~lightweight_mutex()
|
||||
{
|
||||
pthread_mutex_destroy(&m_);
|
||||
}
|
||||
|
||||
class scoped_lock;
|
||||
friend class scoped_lock;
|
||||
|
||||
class scoped_lock
|
||||
{
|
||||
private:
|
||||
|
||||
pthread_mutex_t & m_;
|
||||
|
||||
scoped_lock(scoped_lock const &);
|
||||
scoped_lock & operator=(scoped_lock const &);
|
||||
|
||||
public:
|
||||
|
||||
scoped_lock(lightweight_mutex & m): m_(m.m_)
|
||||
{
|
||||
pthread_mutex_lock(&m_);
|
||||
}
|
||||
|
||||
~scoped_lock()
|
||||
{
|
||||
pthread_mutex_unlock(&m_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED
|
81
include/boost/detail/lwm_win32.hpp
Normal file
81
include/boost/detail/lwm_win32.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
#ifndef BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost/detail/lwm_win32.hpp
|
||||
//
|
||||
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include <boost/detail/winapi.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class lightweight_mutex
|
||||
{
|
||||
private:
|
||||
|
||||
long l_;
|
||||
|
||||
lightweight_mutex(lightweight_mutex const &);
|
||||
lightweight_mutex & operator=(lightweight_mutex const &);
|
||||
|
||||
public:
|
||||
|
||||
lightweight_mutex(): l_(0)
|
||||
{
|
||||
}
|
||||
|
||||
class scoped_lock;
|
||||
friend class scoped_lock;
|
||||
|
||||
class scoped_lock
|
||||
{
|
||||
private:
|
||||
|
||||
lightweight_mutex & m_;
|
||||
|
||||
scoped_lock(scoped_lock const &);
|
||||
scoped_lock & operator=(scoped_lock const &);
|
||||
|
||||
public:
|
||||
|
||||
explicit scoped_lock(lightweight_mutex & m): m_(m)
|
||||
{
|
||||
while( winapi::InterlockedExchange(&m_.l_, 1) )
|
||||
{
|
||||
winapi::Sleep(0);
|
||||
}
|
||||
}
|
||||
|
||||
~scoped_lock()
|
||||
{
|
||||
winapi::InterlockedExchange(&m_.l_, 0);
|
||||
|
||||
// Note: adding a Sleep(0) here will make
|
||||
// the mutex more fair and will increase the overall
|
||||
// performance of some applications substantially in
|
||||
// high contention situations, but will penalize the
|
||||
// low contention / single thread case up to 5x
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED
|
78
include/boost/detail/lwm_win32_cs.hpp
Normal file
78
include/boost/detail/lwm_win32_cs.hpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#ifndef BOOST_DETAIL_LWM_WIN32_CS_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_LWM_WIN32_CS_HPP_INCLUDED
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost/detail/lwm_win32_cs.hpp
|
||||
//
|
||||
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include <boost/detail/winapi.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class lightweight_mutex
|
||||
{
|
||||
private:
|
||||
|
||||
winapi::critical_section cs_;
|
||||
|
||||
lightweight_mutex(lightweight_mutex const &);
|
||||
lightweight_mutex & operator=(lightweight_mutex const &);
|
||||
|
||||
public:
|
||||
|
||||
lightweight_mutex()
|
||||
{
|
||||
winapi::InitializeCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
~lightweight_mutex()
|
||||
{
|
||||
winapi::DeleteCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
class scoped_lock;
|
||||
friend class scoped_lock;
|
||||
|
||||
class scoped_lock
|
||||
{
|
||||
private:
|
||||
|
||||
lightweight_mutex & m_;
|
||||
|
||||
scoped_lock(scoped_lock const &);
|
||||
scoped_lock & operator=(scoped_lock const &);
|
||||
|
||||
public:
|
||||
|
||||
explicit scoped_lock(lightweight_mutex & m): m_(m)
|
||||
{
|
||||
winapi::EnterCriticalSection(&m_.cs_);
|
||||
}
|
||||
|
||||
~scoped_lock()
|
||||
{
|
||||
winapi::LeaveCriticalSection(&m_.cs_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_LWM_WIN32_CS_HPP_INCLUDED
|
136
include/boost/detail/shared_array_nmt.hpp
Normal file
136
include/boost/detail/shared_array_nmt.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifndef BOOST_DETAIL_SHARED_ARRAY_NMT_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_SHARED_ARRAY_NMT_HPP_INCLUDED
|
||||
|
||||
//
|
||||
// detail/shared_array_nmt.hpp - shared_array.hpp without member templates
|
||||
//
|
||||
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
|
||||
// Copyright (c) 2001, 2002 Peter Dimov
|
||||
//
|
||||
// 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/libs/smart_ptr/shared_array.htm for documentation.
|
||||
//
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/checked_delete.hpp>
|
||||
#include <boost/detail/atomic_count.hpp>
|
||||
|
||||
#include <cstddef> // for std::ptrdiff_t
|
||||
#include <algorithm> // for std::swap
|
||||
#include <functional> // for std::less
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<class T> class shared_array
|
||||
{
|
||||
private:
|
||||
|
||||
typedef detail::atomic_count count_type;
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
|
||||
explicit shared_array(T * p = 0): px(p)
|
||||
{
|
||||
try // prevent leak if new throws
|
||||
{
|
||||
pn = new count_type(1);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
checked_array_delete(p);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
~shared_array()
|
||||
{
|
||||
if(--*pn == 0)
|
||||
{
|
||||
checked_array_delete(px);
|
||||
delete pn;
|
||||
}
|
||||
}
|
||||
|
||||
shared_array(shared_array const & r) : px(r.px) // never throws
|
||||
{
|
||||
pn = r.pn;
|
||||
++*pn;
|
||||
}
|
||||
|
||||
shared_array & operator=(shared_array const & r)
|
||||
{
|
||||
shared_array(r).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset(T * p = 0)
|
||||
{
|
||||
BOOST_ASSERT(p == 0 || p != px);
|
||||
shared_array(p).swap(*this);
|
||||
}
|
||||
|
||||
T * get() const // never throws
|
||||
{
|
||||
return px;
|
||||
}
|
||||
|
||||
T & operator[](std::ptrdiff_t i) const // never throws
|
||||
{
|
||||
BOOST_ASSERT(px != 0);
|
||||
BOOST_ASSERT(i >= 0);
|
||||
return px[i];
|
||||
}
|
||||
|
||||
long use_count() const // never throws
|
||||
{
|
||||
return *pn;
|
||||
}
|
||||
|
||||
bool unique() const // never throws
|
||||
{
|
||||
return *pn == 1;
|
||||
}
|
||||
|
||||
void swap(shared_array<T> & other) // never throws
|
||||
{
|
||||
std::swap(px, other.px);
|
||||
std::swap(pn, other.pn);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
T * px; // contained pointer
|
||||
count_type * pn; // ptr to reference counter
|
||||
|
||||
}; // shared_array
|
||||
|
||||
template<class T, class U> inline bool operator==(shared_array<T> const & a, shared_array<U> const & b)
|
||||
{
|
||||
return a.get() == b.get();
|
||||
}
|
||||
|
||||
template<class T, class U> inline bool operator!=(shared_array<T> const & a, shared_array<U> const & b)
|
||||
{
|
||||
return a.get() != b.get();
|
||||
}
|
||||
|
||||
template<class T> inline bool operator<(shared_array<T> const & a, shared_array<T> const & b)
|
||||
{
|
||||
return std::less<T*>()(a.get(), b.get());
|
||||
}
|
||||
|
||||
template<class T> void swap(shared_array<T> & a, shared_array<T> & b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_SHARED_ARRAY_NMT_HPP_INCLUDED
|
392
include/boost/detail/shared_count.hpp
Normal file
392
include/boost/detail/shared_count.hpp
Normal file
@@ -0,0 +1,392 @@
|
||||
#ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// detail/shared_count.hpp
|
||||
//
|
||||
// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#ifndef BOOST_NO_AUTO_PTR
|
||||
# include <memory>
|
||||
#endif
|
||||
|
||||
#include <boost/checked_delete.hpp>
|
||||
#include <boost/detail/lightweight_mutex.hpp>
|
||||
|
||||
#include <functional> // for std::less
|
||||
#include <exception> // for std::exception
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
class use_count_is_zero: public std::exception
|
||||
{
|
||||
public:
|
||||
|
||||
virtual char const * what() const throw()
|
||||
{
|
||||
return "use_count_is_zero";
|
||||
}
|
||||
};
|
||||
|
||||
class counted_base
|
||||
{
|
||||
private:
|
||||
|
||||
typedef detail::lightweight_mutex mutex_type;
|
||||
|
||||
public:
|
||||
|
||||
counted_base():
|
||||
use_count_(0), weak_count_(0), self_deleter_(&self_delete)
|
||||
{
|
||||
}
|
||||
|
||||
// pre: initial_use_count <= initial_weak_count
|
||||
|
||||
explicit counted_base(long initial_use_count, long initial_weak_count):
|
||||
use_count_(initial_use_count), weak_count_(initial_weak_count), self_deleter_(&self_delete)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~counted_base() // nothrow
|
||||
{
|
||||
}
|
||||
|
||||
// dispose() is called when use_count_ drops to zero, to release
|
||||
// the resources managed by *this.
|
||||
//
|
||||
// counted_base doesn't manage any resources except itself, and
|
||||
// the default implementation is a no-op.
|
||||
//
|
||||
// dispose() is not pure virtual since weak_ptr instantiates a
|
||||
// counted_base in its default constructor.
|
||||
|
||||
virtual void dispose() // nothrow
|
||||
{
|
||||
}
|
||||
|
||||
void add_ref()
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
mutex_type::scoped_lock lock(mtx_);
|
||||
#endif
|
||||
if(use_count_ == 0 && weak_count_ != 0) throw use_count_is_zero();
|
||||
++use_count_;
|
||||
++weak_count_;
|
||||
}
|
||||
|
||||
void release() // nothrow
|
||||
{
|
||||
long new_use_count;
|
||||
long new_weak_count;
|
||||
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
mutex_type::scoped_lock lock(mtx_);
|
||||
#endif
|
||||
new_use_count = --use_count_;
|
||||
new_weak_count = --weak_count_;
|
||||
}
|
||||
|
||||
if(new_use_count == 0)
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
|
||||
if(new_weak_count == 0)
|
||||
{
|
||||
// not a direct 'delete this', because the inlined
|
||||
// release() may use a different heap manager
|
||||
self_deleter_(this);
|
||||
}
|
||||
}
|
||||
|
||||
void weak_add_ref() // nothrow
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
mutex_type::scoped_lock lock(mtx_);
|
||||
#endif
|
||||
++weak_count_;
|
||||
}
|
||||
|
||||
void weak_release() // nothrow
|
||||
{
|
||||
long new_weak_count;
|
||||
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
mutex_type::scoped_lock lock(mtx_);
|
||||
#endif
|
||||
new_weak_count = --weak_count_;
|
||||
}
|
||||
|
||||
if(new_weak_count == 0)
|
||||
{
|
||||
self_deleter_(this);
|
||||
}
|
||||
}
|
||||
|
||||
long use_count() const // nothrow
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
mutex_type::scoped_lock lock(mtx_);
|
||||
#endif
|
||||
return use_count_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
counted_base(counted_base const &);
|
||||
counted_base & operator= (counted_base const &);
|
||||
|
||||
static void self_delete(counted_base * p)
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
// inv: use_count_ <= weak_count_
|
||||
|
||||
long use_count_;
|
||||
long weak_count_;
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
mutable mutex_type mtx_;
|
||||
#endif
|
||||
void (*self_deleter_) (counted_base *);
|
||||
};
|
||||
|
||||
inline void intrusive_ptr_add_ref(counted_base * p)
|
||||
{
|
||||
p->add_ref();
|
||||
}
|
||||
|
||||
inline void intrusive_ptr_release(counted_base * p)
|
||||
{
|
||||
p->release();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class P, class D> class counted_base_impl: public counted_base
|
||||
{
|
||||
private:
|
||||
|
||||
P ptr; // copy constructor must not throw
|
||||
D del; // copy constructor must not throw
|
||||
|
||||
counted_base_impl(counted_base_impl const &);
|
||||
counted_base_impl & operator= (counted_base_impl const &);
|
||||
|
||||
public:
|
||||
|
||||
// pre: initial_use_count <= initial_weak_count, d(p) must not throw
|
||||
|
||||
counted_base_impl(P p, D d, long initial_use_count, long initial_weak_count):
|
||||
counted_base(initial_use_count, initial_weak_count), ptr(p), del(d)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void dispose() // nothrow
|
||||
{
|
||||
del(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
class weak_count;
|
||||
|
||||
class shared_count
|
||||
{
|
||||
private:
|
||||
|
||||
counted_base * pi_;
|
||||
|
||||
friend class weak_count;
|
||||
|
||||
template<class P, class D> shared_count(P, D, counted_base const *);
|
||||
|
||||
public:
|
||||
|
||||
shared_count(): pi_(new counted_base(1, 1))
|
||||
{
|
||||
}
|
||||
|
||||
explicit shared_count(counted_base * pi): pi_(pi) // never throws
|
||||
{
|
||||
pi_->add_ref();
|
||||
}
|
||||
|
||||
template<class P, class D> shared_count(P p, D d, void const * = 0): pi_(0)
|
||||
{
|
||||
try
|
||||
{
|
||||
pi_ = new counted_base_impl<P, D>(p, d, 1, 1);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
d(p); // delete p
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<class P, class D> shared_count(P, D, counted_base * pi): pi_(pi)
|
||||
{
|
||||
pi_->add_ref();
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_AUTO_PTR
|
||||
|
||||
// auto_ptr<Y> is special cased to provide the strong guarantee
|
||||
|
||||
template<typename Y>
|
||||
explicit shared_count(std::auto_ptr<Y> & r): pi_(new counted_base_impl< Y *, checked_deleter<Y> >(r.get(), checked_deleter<Y>(), 1, 1))
|
||||
{
|
||||
r.release();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
~shared_count() // nothrow
|
||||
{
|
||||
pi_->release();
|
||||
}
|
||||
|
||||
shared_count(shared_count const & r): pi_(r.pi_) // nothrow
|
||||
{
|
||||
pi_->add_ref();
|
||||
}
|
||||
|
||||
explicit shared_count(weak_count const & r); // throws use_count_is_zero when r.use_count() == 0
|
||||
|
||||
shared_count & operator= (shared_count const & r) // nothrow
|
||||
{
|
||||
counted_base * tmp = r.pi_;
|
||||
tmp->add_ref();
|
||||
pi_->release();
|
||||
pi_ = tmp;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(shared_count & r) // nothrow
|
||||
{
|
||||
counted_base * tmp = r.pi_;
|
||||
r.pi_ = pi_;
|
||||
pi_ = tmp;
|
||||
}
|
||||
|
||||
long use_count() const // nothrow
|
||||
{
|
||||
return pi_->use_count();
|
||||
}
|
||||
|
||||
bool unique() const // nothrow
|
||||
{
|
||||
return pi_->use_count() == 1;
|
||||
}
|
||||
|
||||
friend inline bool operator==(shared_count const & a, shared_count const & b)
|
||||
{
|
||||
return a.pi_ == b.pi_;
|
||||
}
|
||||
|
||||
friend inline bool operator<(shared_count const & a, shared_count const & b)
|
||||
{
|
||||
return std::less<counted_base *>()(a.pi_, b.pi_);
|
||||
}
|
||||
};
|
||||
|
||||
class weak_count
|
||||
{
|
||||
private:
|
||||
|
||||
counted_base * pi_;
|
||||
|
||||
friend class shared_count;
|
||||
|
||||
public:
|
||||
|
||||
weak_count(): pi_(new counted_base(0, 1)) // can throw
|
||||
{
|
||||
}
|
||||
|
||||
weak_count(shared_count const & r): pi_(r.pi_) // nothrow
|
||||
{
|
||||
pi_->weak_add_ref();
|
||||
}
|
||||
|
||||
weak_count(weak_count const & r): pi_(r.pi_) // nothrow
|
||||
{
|
||||
pi_->weak_add_ref();
|
||||
}
|
||||
|
||||
~weak_count() // nothrow
|
||||
{
|
||||
pi_->weak_release();
|
||||
}
|
||||
|
||||
weak_count & operator= (shared_count const & r) // nothrow
|
||||
{
|
||||
counted_base * tmp = r.pi_;
|
||||
tmp->weak_add_ref();
|
||||
pi_->weak_release();
|
||||
pi_ = tmp;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
weak_count & operator= (weak_count const & r) // nothrow
|
||||
{
|
||||
counted_base * tmp = r.pi_;
|
||||
tmp->weak_add_ref();
|
||||
pi_->weak_release();
|
||||
pi_ = tmp;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(weak_count & r) // nothrow
|
||||
{
|
||||
counted_base * tmp = r.pi_;
|
||||
r.pi_ = pi_;
|
||||
pi_ = tmp;
|
||||
}
|
||||
|
||||
long use_count() const // nothrow
|
||||
{
|
||||
return pi_->use_count();
|
||||
}
|
||||
|
||||
friend inline bool operator==(weak_count const & a, weak_count const & b)
|
||||
{
|
||||
return a.pi_ == b.pi_;
|
||||
}
|
||||
|
||||
friend inline bool operator<(weak_count const & a, weak_count const & b)
|
||||
{
|
||||
return std::less<counted_base *>()(a.pi_, b.pi_);
|
||||
}
|
||||
};
|
||||
|
||||
inline shared_count::shared_count(weak_count const & r): pi_(r.pi_)
|
||||
{
|
||||
pi_->add_ref();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED
|
166
include/boost/detail/shared_ptr_nmt.hpp
Normal file
166
include/boost/detail/shared_ptr_nmt.hpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#ifndef BOOST_DETAIL_SHARED_PTR_NMT_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_SHARED_PTR_NMT_HPP_INCLUDED
|
||||
|
||||
//
|
||||
// detail/shared_ptr_nmt.hpp - shared_ptr.hpp without member templates
|
||||
//
|
||||
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
|
||||
// Copyright (c) 2001, 2002 Peter Dimov
|
||||
//
|
||||
// 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/libs/smart_ptr/shared_ptr.htm for documentation.
|
||||
//
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/checked_delete.hpp>
|
||||
#include <boost/detail/atomic_count.hpp>
|
||||
|
||||
#ifndef BOOST_NO_AUTO_PTR
|
||||
#include <memory> // for std::auto_ptr
|
||||
#endif
|
||||
|
||||
#include <algorithm> // for std::swap
|
||||
#include <functional> // for std::less
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<class T> class shared_ptr
|
||||
{
|
||||
private:
|
||||
|
||||
typedef detail::atomic_count count_type;
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
|
||||
explicit shared_ptr(T * p = 0): px(p)
|
||||
{
|
||||
try // prevent leak if new throws
|
||||
{
|
||||
pn = new count_type(1);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
checked_delete(p);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
~shared_ptr()
|
||||
{
|
||||
if(--*pn == 0)
|
||||
{
|
||||
checked_delete(px);
|
||||
delete pn;
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr(shared_ptr const & r): px(r.px) // never throws
|
||||
{
|
||||
pn = r.pn;
|
||||
++*pn;
|
||||
}
|
||||
|
||||
shared_ptr & operator=(shared_ptr const & r)
|
||||
{
|
||||
shared_ptr(r).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_AUTO_PTR
|
||||
|
||||
explicit shared_ptr(std::auto_ptr<T> & r)
|
||||
{
|
||||
pn = new count_type(1); // may throw
|
||||
px = r.release(); // fix: moved here to stop leak if new throws
|
||||
}
|
||||
|
||||
shared_ptr & operator=(std::auto_ptr<T> & r)
|
||||
{
|
||||
shared_ptr(r).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void reset(T * p = 0)
|
||||
{
|
||||
BOOST_ASSERT(p == 0 || p != px);
|
||||
shared_ptr(p).swap(*this);
|
||||
}
|
||||
|
||||
T & operator*() const // never throws
|
||||
{
|
||||
BOOST_ASSERT(px != 0);
|
||||
return *px;
|
||||
}
|
||||
|
||||
T * operator->() const // never throws
|
||||
{
|
||||
BOOST_ASSERT(px != 0);
|
||||
return px;
|
||||
}
|
||||
|
||||
T * get() const // never throws
|
||||
{
|
||||
return px;
|
||||
}
|
||||
|
||||
long use_count() const // never throws
|
||||
{
|
||||
return *pn;
|
||||
}
|
||||
|
||||
bool unique() const // never throws
|
||||
{
|
||||
return *pn == 1;
|
||||
}
|
||||
|
||||
void swap(shared_ptr<T> & other) // never throws
|
||||
{
|
||||
std::swap(px, other.px);
|
||||
std::swap(pn, other.pn);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
T * px; // contained pointer
|
||||
count_type * pn; // ptr to reference counter
|
||||
};
|
||||
|
||||
template<class T, class U> inline bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b)
|
||||
{
|
||||
return a.get() == b.get();
|
||||
}
|
||||
|
||||
template<class T, class U> inline bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b)
|
||||
{
|
||||
return a.get() != b.get();
|
||||
}
|
||||
|
||||
template<class T> inline bool operator<(shared_ptr<T> const & a, shared_ptr<T> const & b)
|
||||
{
|
||||
return std::less<T*>()(a.get(), b.get());
|
||||
}
|
||||
|
||||
template<class T> void swap(shared_ptr<T> & a, shared_ptr<T> & b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
// get_pointer() enables boost::mem_fn to recognize shared_ptr
|
||||
|
||||
template<class T> inline T * get_pointer(shared_ptr<T> const & p)
|
||||
{
|
||||
return p.get();
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_SHARED_PTR_NMT_HPP_INCLUDED
|
75
include/boost/detail/winapi.hpp
Normal file
75
include/boost/detail/winapi.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef BOOST_DETAIL_WINAPI_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_WINAPI_HPP_INCLUDED
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost/detail/winapi.hpp - a lightweight version of <windows.h>
|
||||
//
|
||||
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
namespace winapi
|
||||
{
|
||||
|
||||
typedef long long_type;
|
||||
typedef unsigned long dword_type;
|
||||
typedef void * handle_type;
|
||||
|
||||
#if defined(_WIN64)
|
||||
|
||||
typedef __int64 int_ptr_type;
|
||||
typedef unsigned __int64 uint_ptr_type;
|
||||
typedef __int64 long_ptr_type;
|
||||
typedef unsigned __int64 ulong_ptr_type;
|
||||
|
||||
#else
|
||||
|
||||
typedef int int_ptr_type;
|
||||
typedef unsigned int uint_ptr_type;
|
||||
typedef long long_ptr_type;
|
||||
typedef unsigned long ulong_ptr_type;
|
||||
|
||||
#endif
|
||||
|
||||
struct critical_section
|
||||
{
|
||||
struct critical_section_debug * DebugInfo;
|
||||
long_type LockCount;
|
||||
long_type RecursionCount;
|
||||
handle_type OwningThread;
|
||||
handle_type LockSemaphore;
|
||||
ulong_ptr_type SpinCount;
|
||||
};
|
||||
|
||||
extern "C" __declspec(dllimport) long_type __stdcall InterlockedIncrement(long_type volatile *);
|
||||
extern "C" __declspec(dllimport) long_type __stdcall InterlockedDecrement(long_type volatile *);
|
||||
extern "C" __declspec(dllimport) long_type __stdcall InterlockedExchange(long_type volatile *, long_type);
|
||||
|
||||
extern "C" __declspec(dllimport) void __stdcall Sleep(dword_type);
|
||||
|
||||
extern "C" __declspec(dllimport) void __stdcall InitializeCriticalSection(critical_section *);
|
||||
extern "C" __declspec(dllimport) void __stdcall EnterCriticalSection(critical_section *);
|
||||
extern "C" __declspec(dllimport) void __stdcall LeaveCriticalSection(critical_section *);
|
||||
extern "C" __declspec(dllimport) void __stdcall DeleteCriticalSection(critical_section *);
|
||||
|
||||
} // namespace winapi
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_WINAPI_HPP_INCLUDED
|
202
include/boost/intrusive_ptr.hpp
Normal file
202
include/boost/intrusive_ptr.hpp
Normal file
@@ -0,0 +1,202 @@
|
||||
#ifndef BOOST_INTRUSIVE_PTR_HPP_INCLUDED
|
||||
#define BOOST_INTRUSIVE_PTR_HPP_INCLUDED
|
||||
|
||||
//
|
||||
// intrusive_ptr.hpp
|
||||
//
|
||||
// Copyright (c) 2001, 2002 Peter Dimov
|
||||
//
|
||||
// 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/libs/smart_ptr/intrusive_ptr.html for documentation.
|
||||
//
|
||||
|
||||
#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4284) // odd return type for operator->
|
||||
#endif
|
||||
|
||||
#include <functional> // std::less
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
//
|
||||
// intrusive_ptr
|
||||
//
|
||||
// A smart pointer that uses intrusive reference counting.
|
||||
//
|
||||
// Relies on unqualified calls to
|
||||
//
|
||||
// void intrusive_ptr_add_ref(T * p);
|
||||
// void intrusive_ptr_release(T * p);
|
||||
//
|
||||
// (p != 0)
|
||||
//
|
||||
// The object is responsible for destroying itself.
|
||||
//
|
||||
|
||||
template<class T> class intrusive_ptr
|
||||
{
|
||||
private:
|
||||
|
||||
typedef intrusive_ptr this_type;
|
||||
|
||||
public:
|
||||
|
||||
intrusive_ptr(): p_(0)
|
||||
{
|
||||
}
|
||||
|
||||
intrusive_ptr(T * p): p_(p)
|
||||
{
|
||||
if(p_ != 0) intrusive_ptr_add_ref(p_);
|
||||
}
|
||||
|
||||
~intrusive_ptr()
|
||||
{
|
||||
if(p_ != 0) intrusive_ptr_release(p_);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
|
||||
template<class U> intrusive_ptr(intrusive_ptr<U> const & rhs): p_(rhs.get())
|
||||
{
|
||||
if(p_ != 0) intrusive_ptr_add_ref(p_);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
intrusive_ptr(intrusive_ptr const & rhs): p_(rhs.p_)
|
||||
{
|
||||
if(p_ != 0) intrusive_ptr_add_ref(p_);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
|
||||
template<class U> intrusive_ptr & operator=(intrusive_ptr<U> const & rhs)
|
||||
{
|
||||
this_type(rhs).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
intrusive_ptr & operator=(intrusive_ptr const & rhs)
|
||||
{
|
||||
this_type(rhs).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
intrusive_ptr & operator=(T * rhs)
|
||||
{
|
||||
this_type(rhs).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(intrusive_ptr & rhs)
|
||||
{
|
||||
T * tmp = p_;
|
||||
p_ = rhs.p_;
|
||||
rhs.p_ = tmp;
|
||||
}
|
||||
|
||||
T * get() const
|
||||
{
|
||||
return p_;
|
||||
}
|
||||
|
||||
T & operator*() const
|
||||
{
|
||||
return *p_;
|
||||
}
|
||||
|
||||
T * operator->() const
|
||||
{
|
||||
return p_;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return p_ == 0;
|
||||
}
|
||||
|
||||
typedef bool (intrusive_ptr::*bool_type) () const;
|
||||
|
||||
operator bool_type () const
|
||||
{
|
||||
return p_ == 0? 0: &intrusive_ptr::empty;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
T * p_;
|
||||
};
|
||||
|
||||
template<class T> void swap(intrusive_ptr<T> & lhs, intrusive_ptr<T> & rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template<class T, class U> intrusive_ptr<T> shared_dynamic_cast(intrusive_ptr<U> const & p)
|
||||
{
|
||||
return dynamic_cast<T *>(p.get());
|
||||
}
|
||||
|
||||
template<class T, class U> intrusive_ptr<T> shared_static_cast(intrusive_ptr<U> const & p)
|
||||
{
|
||||
return static_cast<T *>(p.get());
|
||||
}
|
||||
|
||||
template<class T, class U> inline bool operator==(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b)
|
||||
{
|
||||
return a.get() == b.get();
|
||||
}
|
||||
|
||||
template<class T, class U> inline bool operator!=(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b)
|
||||
{
|
||||
return a.get() != b.get();
|
||||
}
|
||||
|
||||
template<class T> inline bool operator<(intrusive_ptr<T> const & a, intrusive_ptr<T> const & b)
|
||||
{
|
||||
return std::less<T *>(a.get(), b.get());
|
||||
}
|
||||
|
||||
template<class T> inline bool operator==(intrusive_ptr<T> const & a, T * b)
|
||||
{
|
||||
return a.get() == b;
|
||||
}
|
||||
|
||||
template<class T> inline bool operator!=(intrusive_ptr<T> const & a, T * b)
|
||||
{
|
||||
return a.get() != b;
|
||||
}
|
||||
|
||||
template<class T> inline bool operator==(T * a, intrusive_ptr<T> const & b)
|
||||
{
|
||||
return a == b.get();
|
||||
}
|
||||
|
||||
template<class T> inline bool operator!=(T * a, intrusive_ptr<T> const & b)
|
||||
{
|
||||
return a != b.get();
|
||||
}
|
||||
|
||||
// mem_fn support
|
||||
|
||||
template<class T> T * get_pointer(intrusive_ptr<T> const & p)
|
||||
{
|
||||
return p.get();
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // #ifndef BOOST_INTRUSIVE_PTR_HPP_INCLUDED
|
86
include/boost/scoped_array.hpp
Normal file
86
include/boost/scoped_array.hpp
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED
|
||||
#define BOOST_SCOPED_ARRAY_HPP_INCLUDED
|
||||
|
||||
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
|
||||
// Copyright (c) 2001, 2002 Peter Dimov
|
||||
//
|
||||
// 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/libs/smart_ptr/scoped_array.htm for documentation.
|
||||
//
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/checked_delete.hpp>
|
||||
#include <boost/config.hpp> // in case ptrdiff_t not in std
|
||||
#include <cstddef> // for std::ptrdiff_t
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
// 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(). Use shared_array or std::vector if your needs are more complex.
|
||||
|
||||
template<typename T> class scoped_array // noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
T * ptr;
|
||||
|
||||
scoped_array(scoped_array const &);
|
||||
scoped_array & operator=(scoped_array const &);
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
|
||||
explicit scoped_array(T * p = 0) : ptr(p) // never throws
|
||||
{
|
||||
}
|
||||
|
||||
~scoped_array() // never throws
|
||||
{
|
||||
checked_array_delete(ptr);
|
||||
}
|
||||
|
||||
void reset(T * p = 0) // never throws
|
||||
{
|
||||
if (ptr != p)
|
||||
{
|
||||
checked_array_delete(ptr);
|
||||
ptr = p;
|
||||
}
|
||||
}
|
||||
|
||||
T & operator[](std::ptrdiff_t i) const // never throws
|
||||
{
|
||||
BOOST_ASSERT(ptr != 0);
|
||||
BOOST_ASSERT(i >= 0);
|
||||
return ptr[i];
|
||||
}
|
||||
|
||||
T * get() const // never throws
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void swap(scoped_array & b) // never throws
|
||||
{
|
||||
T * tmp = b.ptr;
|
||||
b.ptr = ptr;
|
||||
ptr = tmp;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<class T> inline void swap(scoped_array<T> & a, scoped_array<T> & b) // never throws
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED
|
89
include/boost/scoped_ptr.hpp
Normal file
89
include/boost/scoped_ptr.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#ifndef BOOST_SCOPED_PTR_HPP_INCLUDED
|
||||
#define BOOST_SCOPED_PTR_HPP_INCLUDED
|
||||
|
||||
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
|
||||
// Copyright (c) 2001, 2002 Peter Dimov
|
||||
//
|
||||
// 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/libs/smart_ptr/scoped_ptr.htm for documentation.
|
||||
//
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/checked_delete.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
// 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;
|
||||
// use shared_ptr or std::auto_ptr if your needs are more complex.
|
||||
|
||||
template<typename T> class scoped_ptr // noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
T* ptr;
|
||||
|
||||
scoped_ptr(scoped_ptr const &);
|
||||
scoped_ptr & operator=(scoped_ptr const &);
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
|
||||
explicit scoped_ptr(T * p = 0): ptr(p) // never throws
|
||||
{
|
||||
}
|
||||
|
||||
~scoped_ptr() // never throws
|
||||
{
|
||||
checked_delete(ptr);
|
||||
}
|
||||
|
||||
void reset(T * p = 0) // never throws
|
||||
{
|
||||
if (ptr != p)
|
||||
{
|
||||
checked_delete(ptr);
|
||||
ptr = p;
|
||||
}
|
||||
}
|
||||
|
||||
T & operator*() const // never throws
|
||||
{
|
||||
BOOST_ASSERT(ptr != 0);
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
T * operator->() const // never throws
|
||||
{
|
||||
BOOST_ASSERT(ptr != 0);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
T * get() const // never throws
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void swap(scoped_ptr & b) // never throws
|
||||
{
|
||||
T * tmp = b.ptr;
|
||||
b.ptr = ptr;
|
||||
ptr = tmp;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> inline void swap(scoped_ptr<T> & a, scoped_ptr<T> & b) // never throws
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_SCOPED_PTR_HPP_INCLUDED
|
142
include/boost/shared_array.hpp
Normal file
142
include/boost/shared_array.hpp
Normal file
@@ -0,0 +1,142 @@
|
||||
#ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED
|
||||
#define BOOST_SHARED_ARRAY_HPP_INCLUDED
|
||||
|
||||
//
|
||||
// shared_array.hpp
|
||||
//
|
||||
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
|
||||
// Copyright (c) 2001, 2002 Peter Dimov
|
||||
//
|
||||
// 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/libs/smart_ptr/shared_array.htm for documentation.
|
||||
//
|
||||
|
||||
#include <boost/config.hpp> // for broken compiler workarounds
|
||||
|
||||
#ifndef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
#include <boost/detail/shared_array_nmt.hpp>
|
||||
#else
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/checked_delete.hpp>
|
||||
|
||||
#include <boost/detail/shared_count.hpp>
|
||||
|
||||
#include <cstddef> // for std::ptrdiff_t
|
||||
#include <algorithm> // for std::swap
|
||||
#include <functional> // for std::less
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
//
|
||||
// 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
|
||||
{
|
||||
private:
|
||||
|
||||
// Borland 5.5.1 specific workarounds
|
||||
typedef checked_array_deleter<T> deleter;
|
||||
typedef shared_array<T> this_type;
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
|
||||
explicit shared_array(T * p = 0): px(p), pn(p, deleter())
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// Requirements: D's copy constructor must not throw
|
||||
//
|
||||
// shared_array will release p by calling d(p)
|
||||
//
|
||||
|
||||
template<typename D> shared_array(T * p, D d): px(p), pn(p, d)
|
||||
{
|
||||
}
|
||||
|
||||
// generated copy constructor, assignment, destructor are fine
|
||||
|
||||
void reset(T * p = 0)
|
||||
{
|
||||
BOOST_ASSERT(p == 0 || p != px);
|
||||
this_type(p).swap(*this);
|
||||
}
|
||||
|
||||
template <typename D> void reset(T * p, D d)
|
||||
{
|
||||
this_type(p, d).swap(*this);
|
||||
}
|
||||
|
||||
T & operator[] (std::ptrdiff_t i) const // never throws
|
||||
{
|
||||
BOOST_ASSERT(px != 0);
|
||||
BOOST_ASSERT(i >= 0);
|
||||
return px[i];
|
||||
}
|
||||
|
||||
T * get() const // never throws
|
||||
{
|
||||
return px;
|
||||
}
|
||||
|
||||
bool unique() const // never throws
|
||||
{
|
||||
return pn.unique();
|
||||
}
|
||||
|
||||
long use_count() const // never throws
|
||||
{
|
||||
return pn.use_count();
|
||||
}
|
||||
|
||||
void swap(shared_array<T> & other) // never throws
|
||||
{
|
||||
std::swap(px, other.px);
|
||||
pn.swap(other.pn);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
T * px; // contained pointer
|
||||
detail::shared_count pn; // reference counter
|
||||
|
||||
}; // shared_array
|
||||
|
||||
template<typename T> inline bool operator==(shared_array<T> const & a, shared_array<T> const & b) // never throws
|
||||
{
|
||||
return a.get() == b.get();
|
||||
}
|
||||
|
||||
template<typename T> inline bool operator!=(shared_array<T> const & a, shared_array<T> const & b) // never throws
|
||||
{
|
||||
return a.get() != b.get();
|
||||
}
|
||||
|
||||
template<typename T> inline bool operator<(shared_array<T> const & a, shared_array<T> const & b) // never throws
|
||||
{
|
||||
return std::less<T*>()(a.get(), b.get());
|
||||
}
|
||||
|
||||
template<typename T> void swap(shared_array<T> & a, shared_array<T> & b) // never throws
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
|
||||
#endif // #ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED
|
324
include/boost/shared_ptr.hpp
Normal file
324
include/boost/shared_ptr.hpp
Normal file
@@ -0,0 +1,324 @@
|
||||
#ifndef BOOST_SHARED_PTR_HPP_INCLUDED
|
||||
#define BOOST_SHARED_PTR_HPP_INCLUDED
|
||||
|
||||
//
|
||||
// shared_ptr.hpp
|
||||
//
|
||||
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
|
||||
// Copyright (c) 2001, 2002 Peter Dimov
|
||||
//
|
||||
// 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/libs/smart_ptr/shared_ptr.htm for documentation.
|
||||
//
|
||||
|
||||
#include <boost/config.hpp> // for broken compiler workarounds
|
||||
|
||||
#ifndef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
#include <boost/detail/shared_ptr_nmt.hpp>
|
||||
#else
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/checked_delete.hpp>
|
||||
|
||||
#include <boost/detail/shared_count.hpp>
|
||||
|
||||
#include <memory> // for std::auto_ptr
|
||||
#include <algorithm> // for std::swap
|
||||
#include <functional> // for std::less
|
||||
#include <typeinfo> // for std::bad_cast
|
||||
|
||||
#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4284) // odd return type for operator->
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
struct static_cast_tag {};
|
||||
struct dynamic_cast_tag {};
|
||||
struct polymorphic_cast_tag {};
|
||||
|
||||
template<typename T> struct shared_ptr_traits
|
||||
{
|
||||
typedef T & reference;
|
||||
};
|
||||
|
||||
template<> struct shared_ptr_traits<void>
|
||||
{
|
||||
typedef void reference;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
//
|
||||
// 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 weak_ptr;
|
||||
template<typename T> class intrusive_ptr;
|
||||
|
||||
template<typename T> class shared_ptr
|
||||
{
|
||||
private:
|
||||
|
||||
// Borland 5.5.1 specific workarounds
|
||||
// typedef checked_deleter<T> deleter;
|
||||
typedef shared_ptr<T> this_type;
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
|
||||
shared_ptr(): px(0), pn()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Y>
|
||||
explicit shared_ptr(Y * p): px(p), pn(p, checked_deleter<Y>(), p) // Y must be complete
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// Requirements: D's copy constructor must not throw
|
||||
//
|
||||
// shared_ptr will release p by calling d(p)
|
||||
//
|
||||
|
||||
template<typename Y, typename D> shared_ptr(Y * p, D d): px(p), pn(p, d)
|
||||
{
|
||||
}
|
||||
|
||||
// generated copy constructor, assignment, destructor are fine
|
||||
|
||||
template<typename Y>
|
||||
explicit shared_ptr(weak_ptr<Y> const & r): px(r.px), pn(r.pn) // may throw
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Y>
|
||||
shared_ptr(shared_ptr<Y> const & r): px(r.px), pn(r.pn) // never throws
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Y>
|
||||
shared_ptr(intrusive_ptr<Y> const & r): px(r.get()), pn(r.get()) // never throws
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Y>
|
||||
shared_ptr(shared_ptr<Y> const & r, detail::static_cast_tag): px(static_cast<element_type *>(r.px)), pn(r.pn)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Y>
|
||||
shared_ptr(shared_ptr<Y> const & r, detail::dynamic_cast_tag): px(dynamic_cast<element_type *>(r.px)), pn(r.pn)
|
||||
{
|
||||
if (px == 0) // need to allocate new counter -- the cast failed
|
||||
{
|
||||
pn = detail::shared_count();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Y>
|
||||
shared_ptr(shared_ptr<Y> const & r, detail::polymorphic_cast_tag): px(dynamic_cast<element_type *>(r.px)), pn(r.pn)
|
||||
{
|
||||
if (px == 0)
|
||||
{
|
||||
throw std::bad_cast();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_AUTO_PTR
|
||||
|
||||
template<typename Y>
|
||||
explicit shared_ptr(std::auto_ptr<Y> & r): px(r.get()), pn(r)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_MSVC) || (BOOST_MSVC > 1200)
|
||||
|
||||
template<typename Y>
|
||||
shared_ptr & operator=(shared_ptr<Y> const & r) // never throws
|
||||
{
|
||||
px = r.px;
|
||||
pn = r.pn; // shared_count::op= doesn't throw
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_AUTO_PTR
|
||||
|
||||
template<typename Y>
|
||||
shared_ptr & operator=(std::auto_ptr<Y> & r)
|
||||
{
|
||||
this_type(r).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void reset()
|
||||
{
|
||||
this_type().swap(*this);
|
||||
}
|
||||
|
||||
template<typename Y> void reset(Y * p) // Y must be complete
|
||||
{
|
||||
BOOST_ASSERT(p == 0 || p != px); // catch self-reset errors
|
||||
this_type(p).swap(*this);
|
||||
}
|
||||
|
||||
template<typename Y, typename D> void reset(Y * p, D d)
|
||||
{
|
||||
this_type(p, d).swap(*this);
|
||||
}
|
||||
|
||||
typename detail::shared_ptr_traits<T>::reference operator* () const // never throws
|
||||
{
|
||||
BOOST_ASSERT(px != 0);
|
||||
return *px;
|
||||
}
|
||||
|
||||
T * operator-> () const // never throws
|
||||
{
|
||||
BOOST_ASSERT(px != 0);
|
||||
return px;
|
||||
}
|
||||
|
||||
T * get() const // never throws
|
||||
{
|
||||
return px;
|
||||
}
|
||||
|
||||
bool unique() const // never throws
|
||||
{
|
||||
return pn.unique();
|
||||
}
|
||||
|
||||
long use_count() const // never throws
|
||||
{
|
||||
return pn.use_count();
|
||||
}
|
||||
|
||||
// implicit conversion to "bool"
|
||||
|
||||
typedef long (this_type::*bool_type)() const;
|
||||
|
||||
operator bool_type() const // never throws
|
||||
{
|
||||
return px == 0? 0: &this_type::use_count;
|
||||
}
|
||||
|
||||
bool operator! () const // never throws
|
||||
{
|
||||
return px == 0;
|
||||
}
|
||||
|
||||
void swap(shared_ptr<T> & other) // never throws
|
||||
{
|
||||
std::swap(px, other.px);
|
||||
pn.swap(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)
|
||||
|
||||
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
|
||||
|
||||
private:
|
||||
|
||||
template<typename Y> friend class shared_ptr;
|
||||
template<typename Y> friend class weak_ptr;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
T * px; // contained pointer
|
||||
detail::shared_count pn; // reference counter
|
||||
|
||||
}; // shared_ptr
|
||||
|
||||
template<typename T, typename U> inline bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b)
|
||||
{
|
||||
return a.get() == b.get();
|
||||
}
|
||||
|
||||
template<typename T, typename U> inline bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b)
|
||||
{
|
||||
return a.get() != b.get();
|
||||
}
|
||||
|
||||
#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
|
||||
|
||||
// Resolve the ambiguity between our op!= and the one in rel_ops
|
||||
|
||||
template<typename T> inline bool operator!=(shared_ptr<T> const & a, shared_ptr<T> const & b)
|
||||
{
|
||||
return a.get() != b.get();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T> inline bool operator<(shared_ptr<T> const & a, shared_ptr<T> const & b)
|
||||
{
|
||||
return std::less<T*>()(a.get(), b.get());
|
||||
}
|
||||
|
||||
template<typename T> inline void swap(shared_ptr<T> & a, shared_ptr<T> & b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
template<typename T, typename U> shared_ptr<T> shared_static_cast(shared_ptr<U> const & r)
|
||||
{
|
||||
return shared_ptr<T>(r, detail::static_cast_tag());
|
||||
}
|
||||
|
||||
template<typename T, typename U> shared_ptr<T> shared_dynamic_cast(shared_ptr<U> const & r)
|
||||
{
|
||||
return shared_ptr<T>(r, detail::dynamic_cast_tag());
|
||||
}
|
||||
|
||||
template<typename T, typename U> shared_ptr<T> shared_polymorphic_cast(shared_ptr<U> const & r)
|
||||
{
|
||||
return shared_ptr<T>(r, detail::polymorphic_cast_tag());
|
||||
}
|
||||
|
||||
template<typename T, typename U> shared_ptr<T> shared_polymorphic_downcast(shared_ptr<U> const & r)
|
||||
{
|
||||
BOOST_ASSERT(dynamic_cast<T *>(r.get()) == r.get());
|
||||
return shared_static_cast<T>(r);
|
||||
}
|
||||
|
||||
// get_pointer() enables boost::mem_fn to recognize shared_ptr
|
||||
|
||||
template<typename T> inline T * get_pointer(shared_ptr<T> const & p)
|
||||
{
|
||||
return p.get();
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // #ifndef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
|
||||
#endif // #ifndef BOOST_SHARED_PTR_HPP_INCLUDED
|
9
include/boost/smart_ptr.hpp
Normal file
9
include/boost/smart_ptr.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Boost smart_ptr.hpp header file -----------------------------------------//
|
||||
|
||||
// For compatibility, this header includes the header for the four "classic"
|
||||
// smart pointer class templates.
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/shared_array.hpp>
|
177
include/boost/weak_ptr.hpp
Normal file
177
include/boost/weak_ptr.hpp
Normal file
@@ -0,0 +1,177 @@
|
||||
#ifndef BOOST_WEAK_PTR_HPP_INCLUDED
|
||||
#define BOOST_WEAK_PTR_HPP_INCLUDED
|
||||
|
||||
//
|
||||
// weak_ptr.hpp
|
||||
//
|
||||
// Copyright (c) 2001, 2002 Peter Dimov
|
||||
//
|
||||
// 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/libs/smart_ptr/weak_ptr.htm for documentation.
|
||||
//
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4284) // odd return type for operator->
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<typename T> class weak_ptr
|
||||
{
|
||||
private:
|
||||
|
||||
// Borland 5.5.1 specific workarounds
|
||||
typedef weak_ptr<T> this_type;
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
|
||||
weak_ptr(): px(0), pn()
|
||||
{
|
||||
}
|
||||
|
||||
// generated copy constructor, assignment, destructor are fine
|
||||
|
||||
template<typename Y>
|
||||
weak_ptr(weak_ptr<Y> const & r): px(r.px), pn(r.pn) // never throws
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Y>
|
||||
weak_ptr(shared_ptr<Y> const & r): px(r.px), pn(r.pn) // never throws
|
||||
{
|
||||
}
|
||||
|
||||
#if !defined(BOOST_MSVC) || (BOOST_MSVC > 1200)
|
||||
|
||||
template<typename Y>
|
||||
weak_ptr & operator=(weak_ptr<Y> const & r) // never throws
|
||||
{
|
||||
px = r.px;
|
||||
pn = r.pn;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Y>
|
||||
weak_ptr & operator=(shared_ptr<Y> const & r) // never throws
|
||||
{
|
||||
px = r.px;
|
||||
pn = r.pn;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void reset()
|
||||
{
|
||||
this_type().swap(*this);
|
||||
}
|
||||
|
||||
T * get() const // never throws; unsafe in multithreaded programs!
|
||||
{
|
||||
return pn.use_count() == 0? 0: px;
|
||||
}
|
||||
|
||||
long use_count() const // never throws
|
||||
{
|
||||
return pn.use_count();
|
||||
}
|
||||
|
||||
bool expired() const // never throws
|
||||
{
|
||||
return pn.use_count() == 0;
|
||||
}
|
||||
|
||||
void swap(this_type & other) // never throws
|
||||
{
|
||||
std::swap(px, other.px);
|
||||
pn.swap(other.pn);
|
||||
}
|
||||
|
||||
bool less(this_type const & rhs) const // implementation detail, never throws
|
||||
{
|
||||
return pn < rhs.pn;
|
||||
}
|
||||
|
||||
// Tasteless as this may seem, making all members public allows member templates
|
||||
// to work in the absence of member template friends. (Matthew Langston)
|
||||
|
||||
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
|
||||
|
||||
private:
|
||||
|
||||
template<typename Y> friend class weak_ptr;
|
||||
template<typename Y> friend class shared_ptr;
|
||||
|
||||
#endif
|
||||
|
||||
T * px; // contained pointer
|
||||
detail::weak_count pn; // reference counter
|
||||
|
||||
}; // weak_ptr
|
||||
|
||||
template<class T, class U> inline bool operator==(weak_ptr<T> const & a, weak_ptr<U> const & b)
|
||||
{
|
||||
return a.get() == b.get();
|
||||
}
|
||||
|
||||
template<class T, class U> inline bool operator!=(weak_ptr<T> const & a, weak_ptr<U> const & b)
|
||||
{
|
||||
return a.get() != b.get();
|
||||
}
|
||||
|
||||
#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
|
||||
|
||||
// Resolve the ambiguity between our op!= and the one in rel_ops
|
||||
|
||||
template<typename T> inline bool operator!=(weak_ptr<T> const & a, weak_ptr<T> const & b)
|
||||
{
|
||||
return a.get() != b.get();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<class T> inline bool operator<(weak_ptr<T> const & a, weak_ptr<T> const & b)
|
||||
{
|
||||
return a.less(b);
|
||||
}
|
||||
|
||||
template<class T> void swap(weak_ptr<T> & a, weak_ptr<T> & b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
template<class T> shared_ptr<T> make_shared(weak_ptr<T> const & r) // never throws
|
||||
{
|
||||
// optimization: avoid throw overhead
|
||||
if(r.use_count() == 0)
|
||||
{
|
||||
return shared_ptr<T>();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return shared_ptr<T>(r);
|
||||
}
|
||||
catch(use_count_is_zero const &)
|
||||
{
|
||||
return shared_ptr<T>();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // #ifndef BOOST_WEAK_PTR_HPP_INCLUDED
|
47
index.htm
Normal file
47
index.htm
Normal file
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>Boost Smart Pointer Library</title>
|
||||
</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 smart pointer library includes five smart pointer class templates. Smart
|
||||
pointers ease the management of memory dynamically allocated with C++ <b>new</b>
|
||||
expressions. In addition, <b>scoped_ptr</b> can ease the management of memory
|
||||
dynamically allocated in other ways.</p>
|
||||
<ul>
|
||||
<li><a href="smart_ptr.htm">Documentation</a> (HTML).</li>
|
||||
<li>Header <a href="../../boost/scoped_ptr.hpp">scoped_ptr.hpp</a>.</li>
|
||||
<li>Header <a href="../../boost/scoped_array.hpp">scoped_array.hpp</a>.</li>
|
||||
<li>Header <a href="../../boost/shared_ptr.hpp">shared_ptr.hpp</a>.</li>
|
||||
<li>Header <a href="../../boost/shared_array.hpp">shared_array.hpp</a>.</li>
|
||||
<li>Header <a href="../../boost/weak_ptr.hpp">weak_ptr.hpp</a>.</li>
|
||||
<li>Test program <a href="smart_ptr_test.cpp">smart_ptr_test.cpp</a>.</li>
|
||||
<li>Originally submitted by
|
||||
<a href="../../people/greg_colvin.htm">Greg Colvin</a> and
|
||||
<a href="../../people/beman_dawes.html">Beman Dawes</a>,
|
||||
currently maintained by
|
||||
<a href="../../people/peter_dimov.htm">Peter Dimov</a> and
|
||||
<a href="../../people/darin_adler.htm">Darin Adler</a>.</li>
|
||||
</ul>
|
||||
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B %Y" startspan -->1 February 2002<!--webbot bot="Timestamp" endspan i-checksum="14885" -->.</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
BIN
msvcspeed.gif
Normal file
BIN
msvcspeed.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
145
scoped_array.htm
Normal file
145
scoped_array.htm
Normal file
@@ -0,0 +1,145 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>scoped_array</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="middle" width="277" height="86"><a name="scoped_array">scoped_array</a> class template</h1>
|
||||
|
||||
<p>The <b>scoped_array</b> class template stores a pointer to a dynamically allocated
|
||||
array. (Dynamically allocated arrays are allocated with the C++ <b>new[]</b>
|
||||
expression.) The array pointed to is guaranteed to be deleted,
|
||||
either on destruction of the <b>scoped_array</b>, or via an explicit <b>reset</b>.</p>
|
||||
|
||||
<p>The <b>scoped_array</b> template is a simple solution for simple
|
||||
needs. It supplies a basic "resource acquisition is
|
||||
initialization" facility, without shared-ownership or transfer-of-ownership
|
||||
semantics. 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.
|
||||
Because it is <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 <b>scoped_array</b> 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.
|
||||
See <a href="shared_array.htm"><b>shared_array</b></a>
|
||||
if <b>scoped_array</b> does not meet your needs.</p>
|
||||
|
||||
<p>It cannot correctly hold a pointer to a single object.
|
||||
See <a href="scoped_ptr.htm"><b>scoped_ptr</b></a>
|
||||
for that usage.</p>
|
||||
|
||||
<p>A <b>std::vector</b> is an alternative to a <b>scoped_array</b> that is
|
||||
a bit heavier duty but far more flexible.
|
||||
A <b>boost::array</b> is an alternative that does not use dynamic allocation.</p>
|
||||
|
||||
<p>The class template is parameterized on <b>T</b>, the type of the object
|
||||
pointed to. <b>T</b> must meet the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h2>Synopsis</h2>
|
||||
|
||||
<pre>namespace boost {
|
||||
|
||||
template<typename T> class scoped_array : <a href="../utility/utility.htm#noncopyable">noncopyable</a> {
|
||||
|
||||
public:
|
||||
typedef T <a href="#element_type">element_type</a>;
|
||||
|
||||
explicit <a href="#ctor">scoped_array</a>(T * p = 0); // never throws
|
||||
<a href="#~scoped_array">~scoped_array</a>(); // never throws
|
||||
|
||||
void <a href="#reset">reset</a>(T * p = 0); // never throws
|
||||
|
||||
T & <a href="#operator[]">operator[]</a>(std::size_t i) const; // never throws
|
||||
T * <a href="#get">get</a>() const; // never throws
|
||||
|
||||
void <a href="#swap">swap</a>(scoped_array & b); // never throws
|
||||
};
|
||||
|
||||
template<typename T> void <a href="#free-swap">swap</a>(scoped_array<T> & a, scoped_array<T> & b); // never throws
|
||||
|
||||
}</pre>
|
||||
|
||||
<h2>Members</h2>
|
||||
|
||||
<h3>
|
||||
<a name="element_type">element_type</a></h3>
|
||||
<pre>typedef T element_type;</pre>
|
||||
<p>Provides the type of the stored pointer.</p>
|
||||
|
||||
<h3><a name="ctor">constructors</a></h3>
|
||||
<pre>explicit scoped_array(T * p = 0); // never throws</pre>
|
||||
<p>Constructs a <b>scoped_array</b>, storing a copy of <b>p</b>, which must
|
||||
have been allocated via a C++ <b>new</b>[] expression or be 0.
|
||||
<b>T</b> is not required be a complete type.
|
||||
See the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h3><a name="~scoped_array">destructor</a></h3>
|
||||
<pre>~scoped_array(); // never throws</pre>
|
||||
<p>Deletes the array pointed to by the stored pointer.
|
||||
Note that <b>delete[]</b> on a pointer with a value of 0 is harmless.
|
||||
The guarantee that this does not throw exceptions depends on the requirement that the
|
||||
deleted array's objects' destructors do not throw exceptions.
|
||||
See the smart pointer <a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h3><a name="reset">reset</a></h3>
|
||||
<pre>void reset(T * p = 0); // never throws</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++ <b>new[]</b> expression or be 0.
|
||||
The guarantee that this does not throw exceptions depends on the requirement that the
|
||||
deleted array's objects' destructors do not throw exceptions.
|
||||
See the smart pointer <a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h3><a name="operator[]">subscripting</a></h3>
|
||||
<pre>T & operator[](std::size_t i) const; // never throws</pre>
|
||||
<p>Returns a reference to element <b>i</b> of the array pointed to by the
|
||||
stored pointer.
|
||||
Behavior is undefined and almost certainly undesirable if the stored pointer is 0,
|
||||
or if <b>i</b> is less than 0 or is greater than or equal to the number of elements
|
||||
in the array.</p>
|
||||
|
||||
<h3><a name="get">get</a></h3>
|
||||
<pre>T * get() const; // never throws</pre>
|
||||
<p>Returns the stored pointer.
|
||||
<b>T</b> need not be a complete type.
|
||||
See the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h3><a name="swap">swap</a></h3>
|
||||
<pre>void swap(scoped_array & b); // never throws</pre>
|
||||
<p>Exchanges the contents of the two smart pointers.
|
||||
<b>T</b> need not be a complete type.
|
||||
See the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h2><a name="functions">Free Functions</a></h2>
|
||||
|
||||
<h3><a name="free-swap">swap</a></h3>
|
||||
<pre>template<typename T> void swap(scoped_array<T> & a, scoped_array<T> & b); // never throws</pre>
|
||||
<p>Equivalent to <b>a.swap(b)</b>. Matches the interface of <b>std::swap</b>.
|
||||
Provided as an aid to generic programming.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B %Y" startspan-->1 February 2002<!--webbot bot="Timestamp" endspan i-checksum="13964"--></p>
|
||||
|
||||
<p>Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler.
|
||||
Permission to copy, use, modify, sell and distribute this document is granted
|
||||
provided this copyright notice appears in all copies.
|
||||
This document is provided "as is" without express or implied warranty,
|
||||
and with no claim as to its suitability for any purpose.</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
217
scoped_ptr.htm
Normal file
217
scoped_ptr.htm
Normal file
@@ -0,0 +1,217 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>scoped_ptr</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="middle" width="277" height="86"><a name="scoped_ptr">scoped_ptr</a> class template</h1>
|
||||
|
||||
<p>The <b>scoped_ptr</b> class template stores a pointer to a dynamically allocated
|
||||
object. (Dynamically allocated objects are allocated with the C++ <b>new</b>
|
||||
expression.) The object pointed to is guaranteed to be deleted,
|
||||
either on destruction of the <b>scoped_ptr</b>, or via an explicit <b>reset</b>.
|
||||
See the <a href="#example">example</a>.</p>
|
||||
|
||||
<p>The <b>scoped_ptr</b> template is a simple solution for simple
|
||||
needs. It supplies a basic "resource acquisition is
|
||||
initialization" facility, without shared-ownership or transfer-of-ownership
|
||||
semantics. 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.
|
||||
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 <b>scoped_ptr</b> is 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.</p>
|
||||
|
||||
<p>It cannot be used in C++ Standard Library containers.
|
||||
See <a href="shared_ptr.htm"><b>shared_ptr</b></a>
|
||||
or <b>std::auto_ptr</b> if <b>scoped_ptr</b> does not meet your needs.</p>
|
||||
|
||||
<p>It cannot correctly hold a pointer to a
|
||||
dynamically allocated array. See <a href="scoped_array.htm"><b>scoped_array</b></a>
|
||||
for that usage.</p>
|
||||
|
||||
<p>The class template is parameterized on <b>T</b>, the type of the object
|
||||
pointed to. <b>T</b> must meet the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h2>Synopsis</h2>
|
||||
|
||||
<pre>namespace boost {
|
||||
|
||||
template<typename T> class scoped_ptr : <a href="../utility/utility.htm#class noncopyable">noncopyable</a> {
|
||||
|
||||
public:
|
||||
typedef T <a href="#element_type">element_type</a>;
|
||||
|
||||
explicit <a href="#constructors">scoped_ptr</a>(T * p = 0); // never throws
|
||||
<a href="#~scoped_ptr">~scoped_ptr</a>(); // never throws
|
||||
|
||||
void <a href="#reset">reset</a>(T * p = 0); // never throws
|
||||
|
||||
T & <a href="#indirection">operator*</a>() const; // never throws
|
||||
T * <a href="#indirection">operator-></a>() const; // never throws
|
||||
T * <a href="#get">get</a>() const; // never throws
|
||||
|
||||
void <a href="#swap">swap</a>(scoped_ptr & b); // never throws
|
||||
};
|
||||
|
||||
template<typename T> void <a href="#free-swap">swap</a>(scoped_ptr<T> & a, scoped_ptr<T> & b); // never throws
|
||||
|
||||
}</pre>
|
||||
|
||||
<h2>Members</h2>
|
||||
|
||||
<h3><a name="element_type">element_type</a></h3>
|
||||
<pre>typedef T element_type;</pre>
|
||||
<p>Provides the type of the stored pointer.</p>
|
||||
|
||||
<h3><a name="constructors">constructors</a></h3>
|
||||
<pre>explicit scoped_ptr(T * p = 0); // never throws</pre>
|
||||
<p>Constructs a <b>scoped_ptr</b>, storing a copy of <b>p</b>, which must
|
||||
have been allocated via a C++ <b>new</b> expression or be 0.
|
||||
<b>T</b> is not required be a complete type.
|
||||
See the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h3><a name="~scoped_ptr">destructor</a></h3>
|
||||
<pre>~scoped_ptr(); // never throws</pre>
|
||||
<p>Deletes the object pointed to by the stored pointer.
|
||||
Note that <b>delete</b> on a pointer with a value of 0 is harmless.
|
||||
The guarantee that this does not throw exceptions depends on the requirement that the
|
||||
deleted object's destructor does not throw exceptions.
|
||||
See the smart pointer <a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h3><a name="reset">reset</a></h3>
|
||||
<pre>void reset(T * p = 0); // never throws</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++ <b>new</b> expression or be 0.
|
||||
The guarantee that this does not throw exceptions depends on the requirement that the
|
||||
deleted object's destructor does not throw exceptions.
|
||||
See the smart pointer <a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h3><a name="indirection">indirection</a></h3>
|
||||
<pre>T & operator*() const; // never throws</pre>
|
||||
<p>Returns a reference to the object pointed to by the stored pointer.
|
||||
Behavior is undefined if the stored pointer is 0.</p>
|
||||
<pre>T * operator->() const; // never throws</pre>
|
||||
<p>Returns the stored pointer. Behavior is undefined if the stored pointer is 0.</p>
|
||||
|
||||
<h3><a name="get">get</a></h3>
|
||||
<pre>T * get() const; // never throws</pre>
|
||||
<p>Returns the stored pointer.
|
||||
<b>T</b> need not be a complete type.
|
||||
See the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h3><a name="swap">swap</a></h3>
|
||||
<pre>void swap(scoped_ptr & b); // never throws</pre>
|
||||
<p>Exchanges the contents of the two smart pointers.
|
||||
<b>T</b> need not be a complete type.
|
||||
See the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h2><a name="functions">Free Functions</a></h2>
|
||||
|
||||
<h3><a name="free-swap">swap</a></h3>
|
||||
<pre>template<typename T> void swap(scoped_ptr<T> & a, scoped_ptr<T> & b); // never throws</pre>
|
||||
<p>Equivalent to <b>a.swap(b)</b>. Matches the interface of <b>std::swap</b>.
|
||||
Provided as an aid to generic programming.</p>
|
||||
|
||||
<h2><a name="example">Example</a></h2>
|
||||
|
||||
<p>Here's an example that uses <b>scoped_ptr</b>.</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>#include <boost/scoped_ptr.hpp>
|
||||
#include <iostream>
|
||||
|
||||
struct Shoe { ~Shoe() { std::cout << "Buckle my shoe\n"; } };
|
||||
|
||||
class MyClass {
|
||||
boost::scoped_ptr<int> ptr;
|
||||
public:
|
||||
MyClass() : ptr(new int) { *ptr = 0; }
|
||||
int add_one() { return ++*ptr; }
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
boost::scoped_ptr<Shoe> x(new Shoe);
|
||||
MyClass my_instance;
|
||||
std::cout << my_instance.add_one() << '\n';
|
||||
std::cout << my_instance.add_one() << '\n';
|
||||
}</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>The example program produces the beginning of a child's nursery rhyme:</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 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.</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>; by using it you are signaling intent.</p>
|
||||
|
||||
<p>It has been suggested that <b>scoped_ptr<T></b> is equivalent to
|
||||
<b>std::auto_ptr<T> const</b>. Ed Brey pointed out, however, that
|
||||
<b>reset</b> will not work on a <b>std::auto_ptr<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<></b> to an incomplete type to hide the
|
||||
implementation. 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>Frequently Asked Questions</h2>
|
||||
|
||||
<p><b>Q</b>. Why doesn't <b>scoped_ptr</b> have a release() member?<br>
|
||||
<b>A</b>. Because the point of <b>scoped_ptr</b> is to signal intent, not
|
||||
to transfer ownership. 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 -->1 February 2002<!--webbot bot="Timestamp" endspan i-checksum="15110" --></p>
|
||||
|
||||
<p>Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler.
|
||||
Permission to copy, use, modify, sell and distribute this document is granted
|
||||
provided this copyright notice appears in all copies.
|
||||
This document is provided "as is" 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
16
scoped_ptr_example.cpp
Normal 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() {}
|
22
scoped_ptr_example.hpp
Normal file
22
scoped_ptr_example.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// Boost scoped_ptr_example header file ------------------------------------//
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/scoped_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 : private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
example();
|
||||
~example();
|
||||
void do_something();
|
||||
private:
|
||||
class implementation;
|
||||
boost::scoped_ptr< implementation > _imp; // hide implementation details
|
||||
};
|
||||
|
10
scoped_ptr_example_test.cpp
Normal file
10
scoped_ptr_example_test.cpp
Normal 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;
|
||||
}
|
224
shared_array.htm
Normal file
224
shared_array.htm
Normal file
@@ -0,0 +1,224 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>shared_array</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="middle" width="277" height="86">shared_array class template</h1>
|
||||
|
||||
<p>The <b>shared_array</b> class template stores a pointer to a dynamically allocated
|
||||
array. (Dynamically allocated array are allocated with the C++ <b>new[]</b>
|
||||
expression.) The object pointed to is guaranteed to be deleted when
|
||||
the last <b>shared_array</b> pointing to it is destroyed or reset.</p>
|
||||
|
||||
<p>Every <b>shared_array</b> meets the <b>CopyConstructible</b>
|
||||
and <b>Assignable</b> requirements of the C++ Standard Library, and so
|
||||
can be used in standard library containers. Comparison operators
|
||||
are supplied so that <b>shared_array</b> works with
|
||||
the standard library's associative containers.</p>
|
||||
|
||||
<p>Normally, a <b>shared_array</b> cannot correctly hold a pointer to a
|
||||
single dynamically allocated object. See <a href="shared_ptr.htm"><b>shared_ptr</b></a>
|
||||
for that usage.</p>
|
||||
|
||||
<p>Because the implementation uses reference counting, <b>shared_array</b> will not work
|
||||
correctly with cyclic data structures. For example, if <b>main()</b> holds a <b>shared_array</b>
|
||||
to <b>A</b>, which directly or indirectly holds a <b>shared_array</b> back to <b>A</b>,
|
||||
<b>A</b>'s use count will be 2. Destruction of the original <b>shared_array</b>
|
||||
will leave <b>A</b> dangling with a use count of 1.</p>
|
||||
|
||||
<p>A <b>shared_ptr</b> to a <b>std::vector</b> is an alternative to a <b>shared_array</b> that is
|
||||
a bit heavier duty but far more flexible.</p>
|
||||
|
||||
<p>The class template is parameterized on <b>T</b>, the type of the object
|
||||
pointed to. <b>T</b> must meet the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h2>Synopsis</h2>
|
||||
|
||||
<pre>namespace boost {
|
||||
|
||||
template<typename T> class shared_array {
|
||||
|
||||
public:
|
||||
typedef T <a href="#element_type">element_type</a>;
|
||||
|
||||
explicit <a href="#constructors">shared_array</a>(T * p = 0);
|
||||
template<typename D> <a href="#constructors">shared_array</a>(T * p, D d);
|
||||
<a href="#destructor">~shared_array</a>(); // never throws
|
||||
|
||||
<a href="#constructors">shared_array</a>(shared_array const & r); // never throws
|
||||
|
||||
shared_array & <a href="#assignment">operator=</a>(shared_array const & r); // never throws
|
||||
|
||||
void <a href="#reset">reset</a>(T * p = 0);
|
||||
template<typename D> void <a href="#reset">reset</a>(T * p, D d);
|
||||
|
||||
T & <a href="#indexing">operator[]</a>(std::ptrdiff_t i) const() const; // never throws
|
||||
T * <a href="#get">get</a>() const; // never throws
|
||||
|
||||
bool <a href="#unique">unique</a>() const; // never throws
|
||||
long <a href="#use_count">use_count</a>() const; // never throws
|
||||
|
||||
void <a href="#swap">swap</a>(shared_array<T> & b); // never throws
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool <a href="#comparison">operator==</a>(shared_array<T> const & a, shared_array<T> const & b); // never throws
|
||||
template<typename T>
|
||||
bool <a href="#comparison">operator!=</a>(shared_array<T> const & a, shared_array<T> const & b); // never throws
|
||||
template<typename T>
|
||||
bool <a href="#comparison">operator<</a>(shared_array<T> const & a, shared_array<T> const & b); // never throws
|
||||
|
||||
template<typename T> void <a href="#free-swap">swap</a>(shared_array<T> & a, shared_array<T> & b); // never throws
|
||||
|
||||
}</pre>
|
||||
|
||||
<h2>Members</h2>
|
||||
|
||||
<h3><a name="element_type">element_type</a></h3>
|
||||
<pre>typedef T element_type;</pre>
|
||||
<p>Provides the type of the stored pointer.</p>
|
||||
|
||||
<h3><a name="constructors">constructors</a></h3>
|
||||
|
||||
<pre>explicit shared_array(T * p = 0);</pre>
|
||||
<p>Constructs a <b>shared_array</b>, storing a copy of <b>p</b>, which
|
||||
must be a pointer to an array that was allocated via a C++ <b>new[]</b> expression or be 0.
|
||||
Afterwards, the <a href="#use_count">use count</a> is 1 (even if p == 0; see <a href="#destructor">~shared_array</a>).
|
||||
The only exception which may be thrown by this constructor is <b>std::bad_alloc</b>.
|
||||
If an exception is thrown, <b>delete[] p</b> is called.</p>
|
||||
|
||||
<pre>template<typename D> shared_array(T * p, D d);</pre>
|
||||
<p>Constructs a <b>shared_array</b>, storing a copy of <b>p</b> and of <b>d</b>.
|
||||
Afterwards, the <a href="#use_count">use count</a> is 1.
|
||||
<b>D</b>'s copy constructor and destructor must not throw.
|
||||
When the the time comes to delete the array pointed to by <b>p</b>, the object
|
||||
<b>d</b> is used in the statement <b>d(p)</b>. Invoking the object <b>d</b> with
|
||||
parameter <b>p</b> in this way must not throw.
|
||||
The only exception which may be thrown by this constructor is <b>std::bad_alloc</b>.
|
||||
If an exception is thrown, <b>d(p)</b> is called.</p>
|
||||
|
||||
<pre>shared_array(shared_array const & r); // never throws</pre>
|
||||
<p>Constructs a <b>shared_array</b>, as if by storing a copy of the
|
||||
pointer stored in <b>r</b>. Afterwards, the <a href="#use_count">use count</a>
|
||||
for all copies is 1 more than the initial use count.</p>
|
||||
|
||||
<h3><a name="destructor">destructor</a></h3>
|
||||
|
||||
<pre>~shared_array(); // never throws</pre>
|
||||
<p>Decrements the <a href="#use_count">use count</a>. Then, if the use count is 0,
|
||||
deletes the array pointed to by the stored pointer.
|
||||
Note that <b>delete[]</b> on a pointer with a value of 0 is harmless.
|
||||
<b>T</b> need not be a complete type.
|
||||
The guarantee that this does not throw exceptions depends on the requirement that the
|
||||
deleted object's destructor does not throw exceptions.
|
||||
See the smart pointer <a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h3><a name="operator=">assignment</a></h3>
|
||||
|
||||
<pre>shared_array & <a href="#assignment">operator=</a>(shared_array const & r); // never throws</pre>
|
||||
<p>Constructs a new <b>shared_array</b> as described <a href="#constructors">above</a>,
|
||||
then replaces this <b>shared_array</b> with the new one, destroying the replaced object.</p>
|
||||
|
||||
<h3><a name="reset">reset</a></h3>
|
||||
|
||||
<pre>void reset(T * p = 0);</pre>
|
||||
<p>Constructs a new <b>shared_array</b> as described <a href="#constructors">above</a>,
|
||||
then replaces this <b>shared_array</b> with the new one, destroying the replaced object.
|
||||
The only exception which may be thrown is <b>std::bad_alloc</b>. If
|
||||
an exception is thrown, <b>delete[] p</b> is called.</p>
|
||||
|
||||
<pre>template<typename D> void reset(T * p, D d);</pre>
|
||||
<p>Constructs a new <b>shared_array</b> as described <a href="#constructors">above</a>,
|
||||
then replaces this <b>shared_array</b> with the new one, destroying the replaced object.
|
||||
<b>D</b>'s copy constructor must not throw.
|
||||
The only exception which may be thrown is <b>std::bad_alloc</b>. If
|
||||
an exception is thrown, <b>d(p)</b> is called.</p>
|
||||
|
||||
<h3><a name="indirection">indexing</a></h3>
|
||||
<pre>T & operator[](std::size_t i) const; // never throws</pre>
|
||||
<p>Returns a reference to element <b>i</b> of the array pointed to by the stored pointer.
|
||||
Behavior is undefined and almost certainly undesirable if the stored pointer is 0,
|
||||
or if <b>i</b> is less than 0 or is greater than or equal to the number of elements
|
||||
in the array.</p>
|
||||
|
||||
<h3><a name="get">get</a></h3>
|
||||
<pre>T * get() const; // never throws</pre>
|
||||
<p>Returns the stored pointer.
|
||||
<b>T</b> need not be a complete type.
|
||||
See the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h3><a name="unique">unique</a></h3>
|
||||
<pre>bool unique() const; // never throws</pre>
|
||||
<p>Returns true if no other <b>shared_array</b> is sharing ownership of
|
||||
the stored pointer, false otherwise.
|
||||
<b>T</b> need not be a complete type.
|
||||
See the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h3><a name="use_count">use_count</a></h3>
|
||||
<pre>long use_count() const; // never throws</pre>
|
||||
<p>Returns the number of <b>shared_array</b> objects sharing ownership of the
|
||||
stored pointer.
|
||||
<b>T</b> need not be a complete type.
|
||||
See the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
<p>Because <b>use_count</b> is not necessarily efficient to implement for
|
||||
implementations of <b>shared_array</b> that do not use an explicit reference
|
||||
count, it might be removed from some future version. Thus it should
|
||||
be used for debugging purposes only, and not production code.</p>
|
||||
|
||||
<h3><a name="swap">swap</a></h3>
|
||||
<pre>void swap(shared_ptr & b); // never throws</pre>
|
||||
<p>Exchanges the contents of the two smart pointers.
|
||||
<b>T</b> need not be a complete type.
|
||||
See the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
|
||||
<h2><a name="functions">Free Functions</a></h2>
|
||||
|
||||
<h3><a name="comparison">comparison</a></h3>
|
||||
<pre>template<typename T>
|
||||
bool operator==(shared_array<T> const & a, shared_array<T> const & b); // never throws
|
||||
template<typename T>
|
||||
bool operator!=(shared_array<T> const & a, shared_array<T> const & b); // never throws
|
||||
template<typename T>
|
||||
bool operator<(shared_array<T> const & a, shared_array<T> const & b); // never throws</pre>
|
||||
<p>Compares the stored pointers of the two smart pointers.
|
||||
<b>T</b> need not be a complete type.
|
||||
See the smart pointer
|
||||
<a href="smart_ptr.htm#Common requirements">common requirements</a>.</p>
|
||||
<p>The <b>operator<</b> overload is provided to define an ordering so that <b>shared_array</b>
|
||||
objects can be used in associative containers such as <b>std::map</b>.
|
||||
The implementation uses <b>std::less<T *></b> to perform the
|
||||
comparison. This ensures that the comparison is handled correctly, since the
|
||||
standard mandates that relational operations on pointers are unspecified (5.9 [expr.rel]
|
||||
paragraph 2) but <b>std::less<></b> on pointers is well-defined (20.3.3 [lib.comparisons]
|
||||
paragraph 8).</p>
|
||||
|
||||
<h3><a name="free-swap">swap</a></h3>
|
||||
<pre>template<typename T>
|
||||
void swap(shared_array<T> & a, shared_array<T> & b) // never throws</pre>
|
||||
<p>Equivalent to <b>a.swap(b)</b>. Matches the interface of <b>std::swap</b>.
|
||||
Provided as an aid to generic programming.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B %Y" startspan -->8 February 2002<!--webbot bot="Timestamp" i-checksum="38439" endspan --></p>
|
||||
|
||||
<p>Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler.
|
||||
Permission to copy, use, modify, sell and distribute this document is granted
|
||||
provided this copyright notice appears in all copies.
|
||||
This document is provided "as is" without express or implied warranty,
|
||||
and with no claim as to its suitability for any purpose.</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
456
shared_ptr.htm
Normal file
456
shared_ptr.htm
Normal file
@@ -0,0 +1,456 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>shared_ptr</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
<body text="#000000" bgColor="#ffffff">
|
||||
<h1><IMG height="86" alt="c++boost.gif (8819 bytes)" src="../../c++boost.gif" width="277" align="middle">shared_ptr
|
||||
class template</h1>
|
||||
<p><A href="#Introduction">Introduction</A><br>
|
||||
<A href="#Synopsis">Synopsis</A><br>
|
||||
<A href="#Members">Members</A><br>
|
||||
<A href="#functions">Free Functions</A><br>
|
||||
<A href="#example">Example</A><br>
|
||||
<A href="#Handle/Body">Handle/Body Idiom</A><br>
|
||||
<A href="#FAQ">Frequently Asked Questions</A><br>
|
||||
<A href="smarttests.htm">Smart Pointer Timings</A></p>
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
<p>The <b>shared_ptr</b> class template stores a pointer to a dynamically allocated
|
||||
object. (Dynamically allocated objects are allocated with the C++ <b>new</b> expression.)
|
||||
The object pointed to is guaranteed to be deleted when the last <b>shared_ptr</b>
|
||||
pointing to it is destroyed or reset. See the <A href="#example">example</A>.</p>
|
||||
<p>Every <b>shared_ptr</b> meets the <b>CopyConstructible</b> and <b>Assignable</b>
|
||||
requirements of the C++ Standard Library, and so can be used in standard
|
||||
library containers. Comparison operators are supplied so that <b>shared_ptr</b>
|
||||
works with the standard library's associative containers.</p>
|
||||
<p>Normally, a <b>shared_ptr</b> cannot correctly hold a pointer to a dynamically
|
||||
allocated array. See <A href="shared_array.htm"><b>shared_array</b></A> for
|
||||
that usage.</p>
|
||||
<p>Because the implementation uses reference counting, <b>shared_ptr</b> will not
|
||||
work correctly with cyclic data structures. For example, if <b>main()</b> holds
|
||||
a <b>shared_ptr</b> to <b>A</b>, which directly or indirectly holds a <b>shared_ptr</b>
|
||||
back to <b>A</b>, <b>A</b>'s use count will be 2. Destruction of the original <b>shared_ptr</b>
|
||||
will leave <b>A</b> dangling with a use count of 1. Use <A href="weak_ptr.htm">weak_ptr</A>
|
||||
to "break cycles."</p>
|
||||
<p>The class template is parameterized on <b>T</b>, the type of the object pointed
|
||||
to. <STRONG>shared_ptr</STRONG> and most of its member functions place no
|
||||
requirements on <STRONG>T</STRONG>; it is allowed to be an incomplete type, or <STRONG>
|
||||
void</STRONG>. Member functions that do place additional requirements (<A href="#constructors">constructors</A>,
|
||||
<A href="#reset">reset</A>) are explicitly documented below.</p>
|
||||
<P><STRONG>shared_ptr<T></STRONG> can be implicitly converted to <STRONG>shared_ptr<U></STRONG>
|
||||
whenever <STRONG>T*</STRONG> can be implicitly converted to <STRONG>U*</STRONG>.
|
||||
In particular, <STRONG>shared_ptr<T></STRONG> is implicitly convertible
|
||||
to <STRONG>shared_ptr<T const></STRONG>, to <STRONG>shared_ptr<U></STRONG>
|
||||
where <STRONG>U</STRONG> is an accessible base of <STRONG>T</STRONG>, and to <STRONG>
|
||||
shared_ptr<void></STRONG>.</P>
|
||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
||||
<pre>namespace boost {
|
||||
|
||||
class use_count_is_zero: public std::exception;
|
||||
|
||||
template<typename T> class <A href="weak_ptr.htm" >weak_ptr</A>;
|
||||
|
||||
template<typename T> class shared_ptr {
|
||||
|
||||
public:
|
||||
|
||||
typedef T <A href="#element_type" >element_type</A>;
|
||||
|
||||
<A href="#constructors" >shared_ptr</A> ();
|
||||
template<typename Y> explicit <A href="#constructors" >shared_ptr</A> (Y * p);
|
||||
template<typename Y, typename D> <A href="#constructors" >shared_ptr</A>(Y * p, D d);
|
||||
<A href="#destructor" >~shared_ptr</A>(); // never throws
|
||||
|
||||
<A href="#constructors" >shared_ptr</A>(shared_ptr const & r); // never throws
|
||||
template<typename Y> <A href="#constructors" >shared_ptr</A>(shared_ptr<Y> const & r); // never throws
|
||||
explicit <A href="#constructors" >shared_ptr</A>(<A href="weak_ptr.htm" >weak_ptr</A> const & r);
|
||||
template<typename Y> <A href="#constructors" >shared_ptr</A>(std::auto_ptr<Y> & r);
|
||||
|
||||
shared_ptr & <A href="#assignment" >operator=</A>(shared_ptr const & r); // never throws
|
||||
template<typename Y> shared_ptr & <A href="#assignment" >operator=</A>(shared_ptr<Y> const & r); // never throws
|
||||
template<typename Y> shared_ptr & <A href="#assignment" >operator=</A>(std::auto_ptr<Y> & r);
|
||||
|
||||
void <A href="#reset" >reset</A> ();
|
||||
template<typename Y> void <A href="#reset" >reset</A> (Y * p);
|
||||
template<typename Y> template<typename D> void <A href="#reset" >reset</A>(Y * p, D d);
|
||||
|
||||
T & <A href="#indirection" >operator*</A>() const; // never throws
|
||||
T * <A href="#indirection" >operator-></A>() const; // never throws
|
||||
T * <A href="#get" >get</A>() const; // never throws
|
||||
|
||||
bool <A href="#unique" >unique</A>() const; // never throws
|
||||
long <A href="#use_count" >use_count</A>() const; // never throws
|
||||
|
||||
operator <a href="#conversions"><i>implementation-defined-type</i></a> () const; // never throws
|
||||
|
||||
void <A href="#swap" >swap</A>(shared_ptr<T> & b); // never throws
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
bool <A href="#comparison" >operator==</A>(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
|
||||
template<typename T, typename U>
|
||||
bool <A href="#comparison" >operator!=</A>(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
|
||||
template<typename T>
|
||||
bool <A href="#comparison" >operator<</A>(shared_ptr<T> const & a, shared_ptr<T> const & b); // never throws
|
||||
|
||||
template<typename T> void <A href="#free-swap" >swap</A>(shared_ptr<T> & a, shared_ptr<T> & b); // never throws
|
||||
|
||||
template<typename T, typename U>
|
||||
shared_ptr<T> <A href="#shared_static_cast" >shared_static_cast</A>(shared_ptr<U> const & r); // never throws
|
||||
template<typename T, typename U>
|
||||
shared_ptr<T> <A href="#shared_dynamic_cast" >shared_dynamic_cast</A>(shared_ptr<U> const & r);
|
||||
template<typename T, typename U>
|
||||
shared_ptr<T> <A href="#shared_polymorphic_cast" >shared_polymorphic_cast</A>(shared_ptr<U> const & r);
|
||||
template<typename T, typename U>
|
||||
shared_ptr<T> <A href="#shared_polymorphic_downcast" >shared_polymorphic_downcast</A>(shared_ptr<U> const & r); // never throws
|
||||
|
||||
}</pre>
|
||||
<h2><a name="Members">Members</a></h2>
|
||||
<h3><a name="element_type">element_type</a></h3>
|
||||
<pre>typedef T element_type;</pre>
|
||||
<blockquote>
|
||||
<p>Provides the type of the template parameter T.</p>
|
||||
</blockquote>
|
||||
<h3><a name="constructors">constructors</a></h3>
|
||||
<pre>shared_ptr();</pre>
|
||||
<blockquote>
|
||||
<p><b>Effects:</b> Constructs a <b>shared_ptr</b>.</p>
|
||||
<p><b>Postconditions:</b> <A href="#use_count">use count</A> is 1; the stored
|
||||
pointer is 0.</p>
|
||||
<p><b>Throws:</b> <b>std::bad_alloc</b>.</p>
|
||||
<p><b>Exception safety:</b> If an exception is thrown, the constructor has no
|
||||
effect.</p>
|
||||
</blockquote>
|
||||
<pre>template<typename Y> explicit shared_ptr(Y * p);</pre>
|
||||
<blockquote>
|
||||
<p><b>Requirements:</b> <b>p</b> must be convertible to <b>T *</b>. <STRONG>Y</STRONG>
|
||||
must be a complete type. The expression <code>delete p</code> must be
|
||||
well-formed, must not invoke undefined behavior, and must not throw exceptions.
|
||||
</p>
|
||||
<p><b>Effects:</b> Constructs a <b>shared_ptr</b>, storing a copy of <b>p</b>.</p>
|
||||
<p><b>Postconditions:</b> <A href="#use_count">use count</A> is 1.</p>
|
||||
<p><b>Throws:</b> <b>std::bad_alloc</b>.</p>
|
||||
<p><b>Exception safety:</b> If an exception is thrown, <code>delete p</code> is
|
||||
called.</p>
|
||||
<P><STRONG>Notes:</STRONG> <B>p</B> must be a pointer to an object that was
|
||||
allocated via a C++ <B>new</B> expression or be 0. The postcondition that <A href="#use_count">
|
||||
use count</A> is 1 holds even if <b>p</b> is 0; invoking <STRONG>delete</STRONG>
|
||||
on a pointer that has a value of 0 is harmless.</P>
|
||||
</blockquote>
|
||||
<pre>template<typename Y, typename D> shared_ptr(Y * p, D d);</pre>
|
||||
<blockquote>
|
||||
<p><b>Requirements:</b> <B>p</B> must be convertible to <B>T *</B>. The copy
|
||||
constructor and destructor of <b>D</b> must not throw. The expression <code>d(p)</code>
|
||||
must be well-formed, must not invoke undefined behavior, and must not throw
|
||||
exceptions.
|
||||
</p>
|
||||
<p><b>Effects:</b> Constructs a <b>shared_ptr</b>, storing a copy of <b>p</b> and <b>d</b>.</p>
|
||||
<p><b>Postconditions:</b> <A href="#use_count">use count</A> is 1.</p>
|
||||
<p><b>Throws:</b> <b>std::bad_alloc</b>.</p>
|
||||
<p><b>Exception safety:</b> If an exception is thrown, <code>d(p)</code> is called.</p>
|
||||
<p><b>Notes:</b> When the the time comes to delete the object pointed to by <b>p</b>,
|
||||
<code>d(p)</code> is invoked.</p>
|
||||
</blockquote>
|
||||
<pre>shared_ptr(shared_ptr const & r); // never throws
|
||||
template<typename Y> shared_ptr(shared_ptr<Y> const & r); // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Effects:</b> Constructs a <b>shared_ptr</b>, as if by storing a copy of the
|
||||
pointer stored in <STRONG>r</STRONG>.</p>
|
||||
<p><b>Postconditions:</b> <A href="#use_count">use count</A> for all copies is
|
||||
increased by one.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
</blockquote>
|
||||
<pre>explicit shared_ptr(<A href="weak_ptr.htm" >weak_ptr</A> const & r);</pre>
|
||||
<blockquote>
|
||||
<p><b>Effects:</b> Constructs a <b>shared_ptr</b>, as if by storing a copy of the
|
||||
pointer stored in <STRONG>r</STRONG>.</p>
|
||||
<p><b>Postconditions:</b> <A href="#use_count">use count</A> for all copies is
|
||||
increased by one.</p>
|
||||
<p><b>Throws:</b> <b>use_count_is_zero</b> when <code>r.use_count() == 0</code>.</p>
|
||||
<p><b>Exception safety:</b> If an exception is thrown, the constructor has no
|
||||
effect.</p>
|
||||
</blockquote>
|
||||
<pre>template<typename Y> shared_ptr(std::auto_ptr<Y> & r);</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Constructs a <B>shared_ptr</B>, as if by storing a copy of <STRONG>r.release()</STRONG>.</P>
|
||||
<P><B>Postconditions:</B> <A href="#use_count">use count</A> for all copies is
|
||||
increased by one.</P>
|
||||
<P><B>Throws:</B> <B>std::bad_alloc</B>.</P>
|
||||
<P><B>Exception safety:</B> If an exception is thrown, the constructor has no
|
||||
effect.</P>
|
||||
</BLOCKQUOTE>
|
||||
<h3><a name="destructor">destructor</a></h3>
|
||||
<pre>~shared_ptr(); // never throws</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> If <STRONG>*this</STRONG> is the sole owner (<code>use_count() == 1</code>),
|
||||
destroys the object pointed to by the stored pointer.</P>
|
||||
<P><B>Postconditions:</B> <A href="#use_count">use count</A> for all remaining
|
||||
copies is decreased by one.</P>
|
||||
<P><B>Throws:</B> nothing.</P>
|
||||
</BLOCKQUOTE>
|
||||
<H3><a name="assignment">assignment</a></H3>
|
||||
<pre>shared_ptr & operator=(shared_ptr const & r); // never throws
|
||||
template<typename Y> shared_ptr & operator=(shared_ptr<Y> const & r); // never throws
|
||||
template<typename Y> shared_ptr & operator=(std::auto_ptr<Y> & r);</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Equivalent to <code>shared_ptr(r).swap(*this)</code>.</P>
|
||||
<P><B>Notes:</B> The implementation is free to meet the effects (and the implied
|
||||
guarantees) via different means, without creating a temporary. In particular,
|
||||
in the example:</P>
|
||||
<pre>
|
||||
shared_ptr<int> p(new int);
|
||||
shared_ptr<void> q(p);
|
||||
p = p;
|
||||
q = p;
|
||||
</pre>
|
||||
<p>both assignments may be no-ops.</p>
|
||||
</BLOCKQUOTE>
|
||||
<h3><a name="reset">reset</a></h3>
|
||||
<pre>void reset();</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Equivalent to <code>shared_ptr().swap(*this)</code>.</P>
|
||||
</BLOCKQUOTE>
|
||||
<pre>template<typename Y> void reset(Y * p);</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Equivalent to <code>shared_ptr(p).swap(*this)</code>.</P>
|
||||
</BLOCKQUOTE>
|
||||
<pre>template<typename Y, typename D> void reset(Y * p, D d);</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Equivalent to <code>shared_ptr(p, d).swap(*this)</code>.</P>
|
||||
</BLOCKQUOTE>
|
||||
<h3><a name="indirection">indirection</a></h3>
|
||||
<pre>T & operator*() const; // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Requirements:</b> The stored pointer must not be 0.</p>
|
||||
<p><b>Returns:</b> a reference to the object pointed to by the stored pointer.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
</blockquote>
|
||||
<pre>T * operator->() const; // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Requirements:</b> The stored pointer must not be 0.</p>
|
||||
<p><b>Returns:</b> the stored pointer.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
</blockquote>
|
||||
<h3><a name="get">get</a></h3>
|
||||
<pre>T * get() const; // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> the stored pointer.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
</blockquote>
|
||||
<h3><a name="unique">unique</a></h3>
|
||||
<pre>bool unique() const; // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> <code>use_count() == 1</code>.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> <code>unique()</code> may be faster than <code>use_count()</code>.</P>
|
||||
</blockquote>
|
||||
<h3><a name="use_count">use_count</a></h3>
|
||||
<pre>long use_count() const; // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> the number of <b>shared_ptr</b> objects sharing ownership of the
|
||||
stored pointer.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> <code>use_count()</code> is not necessarily efficient. Use only
|
||||
for debugging and testing purposes, not for production code.</P>
|
||||
</blockquote>
|
||||
<h3><a name="conversions">conversions</a></h3>
|
||||
<pre>operator <i>implementation-defined-type</i> () const; // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> an implementation defined value that, when used in boolean
|
||||
contexts, is equivalent to <code>get() != 0</code>.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> This conversion operator allows <b>shared_ptr</b> objects to be
|
||||
used in boolean contexts, like <code>if (p && p->valid()) {}</code>.
|
||||
The actual target type is typically a pointer to a member function, avloiding
|
||||
many of the implicit conversion pitfalls.</P>
|
||||
</blockquote>
|
||||
<h3><a name="swap">swap</a></h3>
|
||||
<pre>void swap(shared_ptr & b); // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Effects:</b> Exchanges the contents of the two smart pointers.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
</blockquote>
|
||||
<h2><a name="functions">Free Functions</a></h2>
|
||||
<h3><a name="comparison">comparison</a></h3>
|
||||
<pre>template<typename T, typename U>
|
||||
bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> <code>a.get() == b.get()</code>.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
</blockquote>
|
||||
<pre>template<typename T, typename U>
|
||||
bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> <code>a.get() != b.get()</code>.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
</blockquote>
|
||||
<pre>template<typename T>
|
||||
bool operator<(shared_ptr<T> const & a, shared_ptr<T> const & b); // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> an implementation-defined value such that <b>operator<</b> is
|
||||
a strict weak ordering as described in section 25.3 <code>[lib.alg.sorting]</code>
|
||||
of the C++ standard.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> Allows <STRONG>shared_ptr</STRONG> objects to be used as keys in
|
||||
associative containers.</P>
|
||||
</blockquote>
|
||||
<h3><a name="free-swap">swap</a></h3>
|
||||
<pre>template<typename T>
|
||||
void swap(shared_ptr<T> & a, shared_ptr<T> & b) // never throws</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Equivalent to <code>a.swap(b)</code>.</P>
|
||||
<P><B>Throws:</B> nothing.</P>
|
||||
<P><B>Notes:</B> Matches the interface of <B>std::swap</B>. Provided as an aid to
|
||||
generic programming.</P>
|
||||
</BLOCKQUOTE>
|
||||
<h3><a name="shared_static_cast">shared_static_cast</a></h3>
|
||||
<pre>template<typename T, typename U>
|
||||
shared_ptr<T> shared_static_cast(shared_ptr<U> const & r); // never throws</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><STRONG>Requires:</STRONG> The expression <code>static_cast<T*>(r.get())</code>
|
||||
must be well-formed.</P>
|
||||
<P><B>Returns:</B> A <STRONG>shared_ptr<T></STRONG> object that stores a copy
|
||||
of <code>static_cast<T*>(r.get())</code> and shares ownership with <b>r</b>.</P>
|
||||
<P><B>Throws:</B> nothing.</P>
|
||||
<P><B>Notes:</B> the seemingly equivalent expression</P>
|
||||
<p><code>shared_ptr<T>(static_cast<T*>(r.get()))</code></p>
|
||||
<p>will eventually result in undefined behavior, attempting to delete the same
|
||||
object twice.</p>
|
||||
</BLOCKQUOTE>
|
||||
<h3><a name="shared_dynamic_cast">shared_dynamic_cast</a></h3>
|
||||
<pre>template<typename T, typename U>
|
||||
shared_ptr<T> shared_dynamic_cast(shared_ptr<U> const & r);</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><STRONG>Requires:</STRONG> The expression <CODE>dynamic_cast<T*>(r.get())</CODE>
|
||||
must be well-formed and its behavior defined.</P>
|
||||
<P><B>Returns:</B></P>
|
||||
<UL>
|
||||
<LI>
|
||||
When <CODE>dynamic_cast<T*>(r.get())</CODE> returns a nonzero value, a <STRONG>
|
||||
shared_ptr<T></STRONG> object that stores a copy of it and shares
|
||||
ownership with <STRONG>r</STRONG>;
|
||||
<LI>
|
||||
Otherwise, a default-constructed <STRONG>shared_ptr<T></STRONG> object.</LI></UL>
|
||||
<P><B>Throws:</B> <STRONG>std::bad_alloc</STRONG>.</P>
|
||||
<P><B>Exception safety:</B> If an exception is thrown, the function has no effect.</P>
|
||||
<P><B>Notes:</B> the seemingly equivalent expression</P>
|
||||
<P><CODE>shared_ptr<T>(dynamic_cast<T*>(r.get()))</CODE></P>
|
||||
<P>will eventually result in undefined behavior, attempting to delete the same
|
||||
object twice.</P>
|
||||
</BLOCKQUOTE>
|
||||
<h3><a name="shared_polymorphic_cast">shared_polymorphic_cast</a></h3>
|
||||
<pre>template<typename T, typename U>
|
||||
shared_ptr<T> shared_polymorphic_cast(shared_ptr<U> const & r);</pre>
|
||||
<BLOCKQUOTE>
|
||||
<p><STRONG>Requires:</STRONG> The expression <CODE><A href="../conversion/cast.htm#Polymorphic_cast">
|
||||
polymorphic_cast</A><T*>(r.get())</CODE> must be well-formed and
|
||||
its behavior defined.</p>
|
||||
<P><B>Returns:</B> A <STRONG>shared_ptr<T></STRONG> object that stores a copy
|
||||
of <CODE><A href="../conversion/cast.htm#Polymorphic_cast">polymorphic_cast</A><T*>(r.get())</CODE>
|
||||
and shares ownership with <B>r</B>.</P>
|
||||
<P><B>Throws:</B> <STRONG>std::bad_cast</STRONG> when the pointer cannot be
|
||||
converted.</P>
|
||||
<P><B>Exception safety:</B> If an exception is thrown, the function has no effect.</P>
|
||||
</BLOCKQUOTE>
|
||||
<h3><a name="shared_polymorphic_downcast">shared_polymorphic_downcast</a></h3>
|
||||
<pre>template<typename T, typename U>
|
||||
shared_ptr<T> shared_polymorphic_downcast(shared_ptr<U> const & r); // never throws</pre>
|
||||
<BLOCKQUOTE>
|
||||
<p><STRONG>Requires:</STRONG> The expression <CODE><A href="../conversion/cast.htm#Polymorphic_cast">
|
||||
polymorphic_downcast</A><T*>(r.get())</CODE> must be well-formed
|
||||
and its behavior defined.</p>
|
||||
<P><B>Returns:</B> A <STRONG>shared_ptr<T></STRONG> object that stores a copy
|
||||
of <CODE><A href="../conversion/cast.htm#Polymorphic_cast">polymorphic_downcast</A><T*>(r.get())</CODE>
|
||||
and shares ownership with <B>r</B>.</P>
|
||||
<P><B>Throws:</B> nothing.</P>
|
||||
</BLOCKQUOTE>
|
||||
<h2><a name="example">Example</a></h2>
|
||||
<p>See <A href="shared_ptr_example.cpp">shared_ptr_example.cpp</A> for a complete
|
||||
example program. The program builds a <b>std::vector</b> and <b>std::set</b> of <b>shared_ptr</b>
|
||||
objects.</p>
|
||||
<p>Note that after the containers have been populated, some of the <b>shared_ptr</b>
|
||||
objects will have a use count of 1 rather than a use count of 2, since the set
|
||||
is a <b>std::set</b> rather than a <b>std::multiset</b>, and thus does not
|
||||
contain duplicate entries. Furthermore, the use count may be even higher at
|
||||
various times while <b>push_back</b> and <b>insert</b> container operations are
|
||||
performed. More complicated yet, the container operations may throw exceptions
|
||||
under a variety of circumstances. Getting the memory management and exception
|
||||
handling in this example right without a smart pointer 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<></b> to an incomplete type to hide the
|
||||
implementation. 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. Note that there is no need for an explicit destructor.
|
||||
Unlike ~scoped_ptr, ~shared_ptr does not require that <b>T</b> be a complete
|
||||
type.</p>
|
||||
<h2><a name="FAQ">Frequently Asked Questions</a></h2>
|
||||
<P><B>Q.</B> There are several variations of shared pointers, with different
|
||||
tradeoffs; why does the smart pointer library supply only a single
|
||||
implementation? It would be useful to be able to experiment with each type so
|
||||
as to find the most suitable for the job at hand?<BR>
|
||||
<b>A.</b> An important goal of <STRONG>shared_ptr</STRONG> is to provide a
|
||||
standard shared-ownership pointer. Having a single pointer type is important
|
||||
for stable library interfaces, since different shared pointers typically cannot
|
||||
interoperate, i.e. a reference counted pointer (used by library A) cannot share
|
||||
ownership with a linked pointer (used by library B.)</P>
|
||||
<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. The <B>shared_ptr</B> template is
|
||||
carefully crafted to meet common needs without extensive parameterization. Some
|
||||
day a highly configurable smart pointer may be invented that is also very easy
|
||||
to use and very hard to misuse. Until then, <B>shared_ptr</B> is the smart
|
||||
pointer of choice for a wide range of applications. (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> I am not convinced. Default parameters can be used where appropriate to
|
||||
hide the complexity. Again, why not policies?<BR>
|
||||
<B>A.</B> Template parameters affect the type. See the answer to the first
|
||||
question above.</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. See <A href="smarttests.htm">timings</A>
|
||||
page. In addition, it is expensive to make a linked list implementation thread
|
||||
safe.</p>
|
||||
<p><b>Q.</b> Why doesn't <b>shared_ptr</b> (or any of 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 requirements 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 a release() function?<br>
|
||||
<b>A.</b> <b>shared_ptr</b> cannot give away ownership unless it's unique()
|
||||
because the other copy will still destroy the object.</p>
|
||||
<p>Consider:</p>
|
||||
<blockquote><pre>shared_ptr<int> a(new int);
|
||||
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2
|
||||
|
||||
int * p = a.release();
|
||||
|
||||
// Who owns p now? b will still call delete on it in its destructor.</pre>
|
||||
</blockquote>
|
||||
<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
|
||||
implementation or a linked list implementation, or some other specific
|
||||
implementation. This is not the intent.</p>
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B %Y" startspan -->
|
||||
04 May 2002<!--webbot bot="Timestamp" i-checksum="38439" endspan --></p>
|
||||
<p>Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler.
|
||||
Copyright 2002 Peter Dimov. Permission to copy, use, modify, sell and
|
||||
distribute this document is granted provided this copyright notice appears in
|
||||
all copies. This document is provided "as is" without express or implied
|
||||
warranty, and with no claim as to its suitability for any purpose.</p>
|
||||
</body>
|
||||
</html>
|
31
shared_ptr_assign_fail.cpp
Normal file
31
shared_ptr_assign_fail.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#if defined(_MSC_VER) && !defined(__ICL)
|
||||
#pragma warning(disable: 4786) // identifier truncated in debug info
|
||||
#pragma warning(disable: 4710) // function not inlined
|
||||
#pragma warning(disable: 4711) // function selected for automatic inline expansion
|
||||
#pragma warning(disable: 4514) // unreferenced inline removed
|
||||
#endif
|
||||
|
||||
//
|
||||
// shared_ptr_assign_fail.cpp - a negative test for shared_ptr assignment
|
||||
//
|
||||
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
bool boost_error(char const *, char const *, char const *, long)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::shared_ptr<int> p;
|
||||
p = new int(42); // assignment must fail
|
||||
return 0;
|
||||
}
|
96
shared_ptr_example.cpp
Normal file
96
shared_ptr_example.cpp
Normal 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/shared_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;
|
||||
}
|
||||
|
19
shared_ptr_example2.cpp
Normal file
19
shared_ptr_example2.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// 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"; }
|
26
shared_ptr_example2.hpp
Normal file
26
shared_ptr_example2.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// Boost shared_ptr_example2 header file -----------------------------------//
|
||||
|
||||
#include <boost/shared_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( const example & );
|
||||
example & operator=( const example & );
|
||||
void do_something();
|
||||
private:
|
||||
class implementation;
|
||||
boost::shared_ptr< implementation > _imp; // hide implementation details
|
||||
};
|
||||
|
15
shared_ptr_example2_test.cpp
Normal file
15
shared_ptr_example2_test.cpp
Normal 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;
|
||||
}
|
181
shared_ptr_mt_test.cpp
Normal file
181
shared_ptr_mt_test.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
#if defined(_MSC_VER) && !defined(__ICL) && !defined(__COMO__)
|
||||
#pragma warning(disable: 4786) // identifier truncated in debug info
|
||||
#pragma warning(disable: 4710) // function not inlined
|
||||
#pragma warning(disable: 4711) // function selected for automatic inline expansion
|
||||
#pragma warning(disable: 4514) // unreferenced inline removed
|
||||
#endif
|
||||
|
||||
//
|
||||
// shared_ptr_mt_test.cpp - tests shared_ptr with multiple threads
|
||||
//
|
||||
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#define BOOST_INCLUDE_MAIN
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
|
||||
// 'portable' thread framework
|
||||
|
||||
class abstract_thread
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~abstract_thread() {}
|
||||
virtual void run() = 0;
|
||||
};
|
||||
|
||||
#if !defined(BOOST_HAS_PTHREADS) && defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
char const * title = "Using Windows threads";
|
||||
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
|
||||
typedef HANDLE pthread_t;
|
||||
|
||||
unsigned __stdcall common_thread_routine(void * pv)
|
||||
{
|
||||
abstract_thread * pt = static_cast<abstract_thread *>(pv);
|
||||
pt->run();
|
||||
delete pt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_create(pthread_t * thread, void const *, unsigned (__stdcall * start_routine) (void*), void* arg)
|
||||
{
|
||||
HANDLE h = (HANDLE)_beginthreadex(0, 0, start_routine, arg, 0, 0);
|
||||
|
||||
if(h != 0)
|
||||
{
|
||||
*thread = h;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1; // return errno;
|
||||
}
|
||||
}
|
||||
|
||||
int pthread_join(pthread_t thread, void ** /*value_ptr*/)
|
||||
{
|
||||
::WaitForSingleObject(thread, INFINITE);
|
||||
::CloseHandle(thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
char const * title = "Using POSIX threads";
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
extern "C" void * common_thread_routine(void * pv)
|
||||
{
|
||||
abstract_thread * pt = static_cast<abstract_thread *>(pv);
|
||||
pt->run();
|
||||
delete pt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
|
||||
template<class F> class thread: public abstract_thread
|
||||
{
|
||||
public:
|
||||
|
||||
explicit thread(F f): f_(f)
|
||||
{
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
f_();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
F f_;
|
||||
};
|
||||
|
||||
template<class F> pthread_t createThread(F f)
|
||||
{
|
||||
std::auto_ptr<abstract_thread> p(new thread<F>(f));
|
||||
|
||||
pthread_t r;
|
||||
|
||||
if(pthread_create(&r, 0, common_thread_routine, p.get()) == 0)
|
||||
{
|
||||
p.release();
|
||||
return r;
|
||||
}
|
||||
|
||||
throw std::runtime_error("createThread failed.");
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
int const n = 1024 * 1024;
|
||||
|
||||
void test(boost::shared_ptr<int> const & pi)
|
||||
{
|
||||
std::vector< boost::shared_ptr<int> > v;
|
||||
|
||||
for(int i = 0; i < n; ++i)
|
||||
{
|
||||
v.push_back(pi);
|
||||
}
|
||||
}
|
||||
|
||||
int const m = 16; // threads
|
||||
|
||||
#if defined(BOOST_LWM_USE_CRITICAL_SECTION)
|
||||
char const * implementation = "critical section";
|
||||
#elif defined(BOOST_LWM_USE_PTHREADS)
|
||||
char const * implementation = "pthread_mutex";
|
||||
#else
|
||||
char const * implementation = "spinlock";
|
||||
#endif
|
||||
|
||||
int test_main( int, char ** )
|
||||
{
|
||||
std::printf("%s: %s, %d threads, %d iterations: ", title, implementation, m, n);
|
||||
|
||||
boost::shared_ptr<int> pi(new int(42));
|
||||
|
||||
std::clock_t t = std::clock();
|
||||
|
||||
pthread_t a[m];
|
||||
|
||||
for(int i = 0; i < m; ++i)
|
||||
{
|
||||
a[i] = createThread( boost::bind(test, pi) );
|
||||
}
|
||||
|
||||
for(int i = 0; i < m; ++i)
|
||||
{
|
||||
pthread_join(a[i], 0);
|
||||
}
|
||||
|
||||
t = std::clock() - t;
|
||||
|
||||
std::printf("\n\n%.3f seconds.\n", static_cast<double>(t) / CLOCKS_PER_SEC);
|
||||
|
||||
return 0;
|
||||
}
|
343
shared_ptr_test.cpp
Normal file
343
shared_ptr_test.cpp
Normal file
@@ -0,0 +1,343 @@
|
||||
#if defined(_MSC_VER) && !defined(__ICL) && !defined(__COMO__)
|
||||
#pragma warning(disable: 4786) // identifier truncated in debug info
|
||||
#pragma warning(disable: 4710) // function not inlined
|
||||
#pragma warning(disable: 4711) // function selected for automatic inline expansion
|
||||
#pragma warning(disable: 4514) // unreferenced inline removed
|
||||
#endif
|
||||
|
||||
//
|
||||
// shared_ptr_test.cpp - a test for shared_ptr.hpp and weak_ptr.hpp
|
||||
//
|
||||
// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#define BOOST_INCLUDE_MAIN
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
bool boost_error(char const *, char const *, char const *, long)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
int cnt = 0;
|
||||
}
|
||||
|
||||
struct X
|
||||
{
|
||||
X()
|
||||
{
|
||||
++cnt;
|
||||
std::cout << "X(" << this << ")::X()\n";
|
||||
}
|
||||
|
||||
~X() // virtual destructor deliberately omitted
|
||||
{
|
||||
--cnt;
|
||||
std::cout << "X(" << this << ")::~X()\n";
|
||||
}
|
||||
|
||||
virtual int id() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
X(X const &);
|
||||
X & operator= (X const &);
|
||||
};
|
||||
|
||||
struct Y: public X
|
||||
{
|
||||
Y()
|
||||
{
|
||||
++cnt;
|
||||
std::cout << "Y(" << this << ")::Y()\n";
|
||||
}
|
||||
|
||||
~Y()
|
||||
{
|
||||
--cnt;
|
||||
std::cout << "Y(" << this << ")::~Y()\n";
|
||||
}
|
||||
|
||||
virtual int id() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Y(Y const &);
|
||||
Y & operator= (Y const &);
|
||||
};
|
||||
|
||||
int * get_object()
|
||||
{
|
||||
++cnt;
|
||||
std::cout << "get_object()\n";
|
||||
return &cnt;
|
||||
}
|
||||
|
||||
void release_object(int * p)
|
||||
{
|
||||
BOOST_TEST(p == &cnt);
|
||||
--cnt;
|
||||
std::cout << "release_object()\n";
|
||||
}
|
||||
|
||||
class Z: public virtual boost::counted_base
|
||||
{
|
||||
public:
|
||||
|
||||
Z()
|
||||
{
|
||||
++cnt;
|
||||
std::cout << "Z(" << this << ")::Z()\n";
|
||||
}
|
||||
|
||||
~Z()
|
||||
{
|
||||
--cnt;
|
||||
std::cout << "Z(" << this << ")::~Z()\n";
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Z(Z const &);
|
||||
Z & operator= (Z const &);
|
||||
};
|
||||
|
||||
template<class T> void test_is_X(boost::shared_ptr<T> const & p)
|
||||
{
|
||||
BOOST_TEST(p->id() == 1);
|
||||
BOOST_TEST((*p).id() == 1);
|
||||
}
|
||||
|
||||
template<class T> void test_is_X(boost::weak_ptr<T> const & p)
|
||||
{
|
||||
BOOST_TEST(p.get() != 0);
|
||||
BOOST_TEST(p.get()->id() == 1);
|
||||
}
|
||||
|
||||
template<class T> void test_is_Y(boost::shared_ptr<T> const & p)
|
||||
{
|
||||
BOOST_TEST(p->id() == 2);
|
||||
BOOST_TEST((*p).id() == 2);
|
||||
}
|
||||
|
||||
template<class T> void test_is_Y(boost::weak_ptr<T> const & p)
|
||||
{
|
||||
BOOST_TEST(p.get() != 0);
|
||||
BOOST_TEST(p.get()->id() == 2);
|
||||
}
|
||||
|
||||
template<class T> void test_eq(T const & a, T const & b)
|
||||
{
|
||||
BOOST_TEST(a == b);
|
||||
BOOST_TEST(!(a != b));
|
||||
BOOST_TEST(!(a < b));
|
||||
BOOST_TEST(!(b < a));
|
||||
}
|
||||
|
||||
template<class T> void test_ne(T const & a, T const & b)
|
||||
{
|
||||
BOOST_TEST(!(a == b));
|
||||
BOOST_TEST(a != b);
|
||||
BOOST_TEST(a < b || b < a);
|
||||
BOOST_TEST(!(a < b && b < a));
|
||||
}
|
||||
|
||||
template<class T, class U> void test_eq2(T const & a, U const & b)
|
||||
{
|
||||
BOOST_TEST(a == b);
|
||||
BOOST_TEST(!(a != b));
|
||||
}
|
||||
|
||||
template<class T, class U> void test_ne2(T const & a, U const & b)
|
||||
{
|
||||
BOOST_TEST(!(a == b));
|
||||
BOOST_TEST(a != b);
|
||||
}
|
||||
|
||||
template<class T> void test_is_zero(boost::shared_ptr<T> const & p)
|
||||
{
|
||||
BOOST_TEST(!p);
|
||||
BOOST_TEST(p.get() == 0);
|
||||
}
|
||||
|
||||
template<class T> void test_is_nonzero(boost::shared_ptr<T> const & p)
|
||||
{
|
||||
BOOST_TEST(p);
|
||||
BOOST_TEST(p.get() != 0);
|
||||
}
|
||||
|
||||
int test_main(int, char * [])
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
{
|
||||
shared_ptr<X> p(new Y);
|
||||
shared_ptr<X> p2(new X);
|
||||
|
||||
test_is_nonzero(p);
|
||||
test_is_nonzero(p2);
|
||||
test_is_Y(p);
|
||||
test_is_X(p2);
|
||||
test_ne(p, p2);
|
||||
|
||||
{
|
||||
shared_ptr<X> q(p);
|
||||
test_eq(p, q);
|
||||
}
|
||||
|
||||
shared_ptr<Y> p3 = shared_dynamic_cast<Y>(p);
|
||||
shared_ptr<Y> p4 = shared_dynamic_cast<Y>(p2);
|
||||
|
||||
test_is_nonzero(p3);
|
||||
test_is_zero(p4);
|
||||
|
||||
BOOST_TEST(p.use_count() == 2);
|
||||
BOOST_TEST(p2.use_count() == 1);
|
||||
BOOST_TEST(p3.use_count() == 2);
|
||||
BOOST_TEST(p4.use_count() == 1);
|
||||
|
||||
test_is_Y(p3);
|
||||
test_eq2(p, p3);
|
||||
test_ne2(p2, p4);
|
||||
|
||||
shared_ptr<void> p5(p);
|
||||
|
||||
test_is_nonzero(p5);
|
||||
test_eq2(p, p5);
|
||||
|
||||
std::cout << "--\n";
|
||||
|
||||
p.reset();
|
||||
p2.reset();
|
||||
p3.reset();
|
||||
p4.reset();
|
||||
|
||||
test_is_zero(p);
|
||||
test_is_zero(p2);
|
||||
test_is_zero(p3);
|
||||
test_is_zero(p4);
|
||||
|
||||
std::cout << "--\n";
|
||||
|
||||
BOOST_TEST(p5.use_count() == 1);
|
||||
|
||||
weak_ptr<X> wp1;
|
||||
|
||||
BOOST_TEST(wp1.use_count() == 0);
|
||||
BOOST_TEST(wp1.get() == 0);
|
||||
|
||||
try
|
||||
{
|
||||
shared_ptr<X> sp1(wp1);
|
||||
BOOST_ERROR("shared_ptr<X> sp1(wp1) failed to throw");
|
||||
}
|
||||
catch(boost::use_count_is_zero const &)
|
||||
{
|
||||
}
|
||||
|
||||
test_is_zero(boost::make_shared(wp1));
|
||||
|
||||
weak_ptr<X> wp2 = shared_static_cast<X>(p5);
|
||||
|
||||
BOOST_TEST(wp2.use_count() == 1);
|
||||
BOOST_TEST(wp2.get() != 0);
|
||||
test_is_Y(wp2);
|
||||
test_ne(wp1, wp2);
|
||||
|
||||
// Scoped to not affect the subsequent use_count() tests.
|
||||
{
|
||||
shared_ptr<X> sp2(wp2);
|
||||
test_is_nonzero(boost::make_shared(wp2));
|
||||
}
|
||||
|
||||
weak_ptr<Y> wp3 = shared_dynamic_cast<Y>(boost::make_shared(wp2));
|
||||
|
||||
BOOST_TEST(wp3.use_count() == 1);
|
||||
BOOST_TEST(wp3.get() != 0);
|
||||
test_eq2(wp2, wp3);
|
||||
|
||||
weak_ptr<X> wp4(wp3);
|
||||
|
||||
BOOST_TEST(wp4.use_count() == 1);
|
||||
BOOST_TEST(wp4.get() != 0);
|
||||
test_eq(wp2, wp4);
|
||||
|
||||
wp1 = p2;
|
||||
BOOST_TEST(wp1.get() == 0);
|
||||
|
||||
// Note the following test. Construction succeeds,
|
||||
// but make_shared() returns a null shared_ptr with
|
||||
// use_count() == 2.
|
||||
|
||||
shared_ptr<X> sp1(wp1);
|
||||
test_is_zero(boost::make_shared(wp1));
|
||||
|
||||
BOOST_TEST(p2.use_count() == 2);
|
||||
BOOST_TEST(sp1.use_count() == 2);
|
||||
BOOST_TEST(wp1.use_count() == 2);
|
||||
|
||||
//
|
||||
|
||||
wp1 = p4;
|
||||
wp1 = wp3;
|
||||
wp1 = wp2;
|
||||
|
||||
BOOST_TEST(wp1.use_count() == 1);
|
||||
BOOST_TEST(wp1.get() != 0);
|
||||
test_eq(wp1, wp2);
|
||||
|
||||
weak_ptr<X> wp5;
|
||||
|
||||
bool b1 = wp1 < wp5;
|
||||
bool b2 = wp5 < wp1;
|
||||
|
||||
p5.reset();
|
||||
|
||||
BOOST_TEST(wp1.use_count() == 0);
|
||||
BOOST_TEST(wp1.get() == 0);
|
||||
|
||||
BOOST_TEST(wp2.use_count() == 0);
|
||||
BOOST_TEST(wp2.get() == 0);
|
||||
|
||||
BOOST_TEST(wp3.use_count() == 0);
|
||||
BOOST_TEST(wp3.get() == 0);
|
||||
|
||||
// Test operator< stability for std::set< weak_ptr<> >
|
||||
// Thanks to Joe Gottman for pointing this out
|
||||
|
||||
BOOST_TEST(b1 == (wp1 < wp5));
|
||||
BOOST_TEST(b2 == (wp5 < wp1));
|
||||
|
||||
{
|
||||
// note that both get_object and release_object deal with int*
|
||||
shared_ptr<void> p6(get_object(), release_object);
|
||||
}
|
||||
|
||||
{
|
||||
// test intrusive counting
|
||||
boost::shared_ptr<void> pv(new Z);
|
||||
boost::shared_ptr<Z> pz = boost::shared_static_cast<Z>(pv);
|
||||
BOOST_TEST(pz.use_count() == pz->use_count());
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_TEST(cnt == 0);
|
||||
|
||||
return 0;
|
||||
}
|
41
shared_ptr_timing_test.cpp
Normal file
41
shared_ptr_timing_test.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#if defined(_MSC_VER) && !defined(__ICL) && !defined(__COMO__)
|
||||
#pragma warning(disable: 4786) // identifier truncated in debug info
|
||||
#pragma warning(disable: 4710) // function not inlined
|
||||
#pragma warning(disable: 4711) // function selected for automatic inline expansion
|
||||
#pragma warning(disable: 4514) // unreferenced inline removed
|
||||
#endif
|
||||
|
||||
//
|
||||
// shared_ptr_timing_test.cpp - use to evaluate the impact of thread safety
|
||||
//
|
||||
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <ctime>
|
||||
|
||||
int const n = 8 * 1024 * 1024;
|
||||
|
||||
int main()
|
||||
{
|
||||
std::vector< boost::shared_ptr<int> > v;
|
||||
boost::shared_ptr<int> pi(new int);
|
||||
|
||||
std::clock_t t = std::clock();
|
||||
|
||||
for(int i = 0; i < n; ++i)
|
||||
{
|
||||
v.push_back(pi);
|
||||
}
|
||||
|
||||
t = std::clock() - t;
|
||||
|
||||
std::cout << static_cast<double>(t) / CLOCKS_PER_SEC << '\n';
|
||||
}
|
207
smart_ptr.htm
Normal file
207
smart_ptr.htm
Normal file
@@ -0,0 +1,207 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>Smart Pointers</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="middle" width="277" height="86">Smart
|
||||
Pointers</h1>
|
||||
|
||||
<p>Smart pointers are objects which store pointers to dynamically allocated
|
||||
(heap) objects. They behave much like built-in C++ pointers except that
|
||||
they automatically delete the object pointed to at the appropriate
|
||||
time. 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 smart pointer library provides five smart pointer class templates:</p>
|
||||
|
||||
<div align="left">
|
||||
<table border="1" cellpadding="4" cellspacing="4">
|
||||
<tr>
|
||||
<td><a href="scoped_ptr.htm"><b>scoped_ptr</b></a></td>
|
||||
<td><a href="../../boost/scoped_ptr.hpp"><boost/scoped_ptr.hpp></a></td>
|
||||
<td>Simple sole ownership of single objects. Noncopyable.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="scoped_array.htm"><b>scoped_array</b></a></td>
|
||||
<td><a href="../../boost/scoped_array.hpp"><boost/scoped_array.hpp></a></td>
|
||||
<td>Simple sole ownership of arrays. Noncopyable.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="shared_ptr.htm"><b>shared_ptr</b></a></td>
|
||||
<td><a href="../../boost/shared_ptr.hpp"><boost/shared_ptr.hpp></a></td>
|
||||
<td>Object ownership shared among multiple pointers</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="shared_array.htm"><b>shared_array</b></a></td>
|
||||
<td><a href="../../boost/shared_array.hpp"><boost/shared_array.hpp></a></td>
|
||||
<td>Array ownership shared among multiple pointers.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="weak_ptr.htm"><b>weak_ptr</b></a></td>
|
||||
<td><a href="../../boost/weak_ptr.hpp"><boost/weak_ptr.hpp></a></td>
|
||||
<td>Non-owning observers of an object owned by <b>shared_ptr</b>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p>These templates are designed to complement the <b>std::auto_ptr</b> template.</p>
|
||||
|
||||
<p>They are examples of the "resource acquisition is initialization"
|
||||
idiom described in Bjarne Stroustrup's "The C++ Programming Language",
|
||||
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="compatibility.htm">compatibility</a> with older versions of
|
||||
the Boost smart pointer library describes some of the changes since earlier versions
|
||||
of the smart pointer implementation.</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 class templates have a template parameter, <b>T</b>, which
|
||||
specifies the type of the object pointed to by the smart pointer. The
|
||||
behavior of the smart pointer templates is undefined if the destructor or <b>operator delete</b>
|
||||
for objects of type <b>T</b> throw exceptions.</p>
|
||||
|
||||
<p><b>T</b> may be an incomplete type at the point of smart pointer
|
||||
declaration. Unless otherwise specified, it is required that <b>T</b>
|
||||
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 the description of the <a href="../utility/utility.htm#checked_delete"><b>checked_delete</b></a>
|
||||
function template.</p>
|
||||
|
||||
<h3>Rationale</h3>
|
||||
|
||||
<p>The requirements on <b>T</b> are carefully crafted to maximize safety
|
||||
yet allow handle-body (also called pimpl) and similar idioms. In these idioms a
|
||||
smart pointer may appear in translation units where <b>T</b> is an
|
||||
incomplete type. This separates interface from implementation and hides
|
||||
implementation from translation units which merely use the interface.
|
||||
Examples described in the documentation for specific smart pointers illustrate
|
||||
use of smart pointers in these idioms.</p>
|
||||
|
||||
<p>Note that <b>scoped_ptr</b> requires that <b>T</b> be a complete type
|
||||
at destruction time, but <b>shared_ptr</b> does not.</p>
|
||||
|
||||
<h2>Exception Safety</h2>
|
||||
|
||||
<p>Several functions in these smart pointer classes are specified as having
|
||||
"no effect" or "no effect except such-and-such" if an
|
||||
exception is thrown. 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. This amounts to a guarantee that there are no detectable side
|
||||
effects. Other functions never throw exceptions. The only exception
|
||||
ever thrown by functions which do throw (assuming <b>T</b> meets the
|
||||
<a href="#Common requirements">common requirements</a>) is <b>std::bad_alloc</b>,
|
||||
and that is thrown only by functions which are explicitly documented as possibly
|
||||
throwing <b>std::bad_alloc</b>.</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 the smart pointer templates contain member functions which can never throw exceptions,
|
||||
because they neither throw exceptions themselves nor call other functions which
|
||||
may throw exceptions. These members are indicated by a comment:
|
||||
<code>// never throws</code>. </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>January 2002. Peter Dimov reworked all four classes, adding features, fixing bugs,
|
||||
and splitting them into four separate headers, and added <b>weak_ptr</b>. See the
|
||||
<a href="compatibility.htm">compatibility</a> page for a summary of the changes.</p>
|
||||
|
||||
<p>May 2001. Vladimir Prus suggested requiring a complete type on
|
||||
destruction. 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 <b>operator ==</b>, <b>operator !=</b>, and <b>std::swap</b>
|
||||
and <b>std::less</b> specializations for shared types.</p>
|
||||
|
||||
<p>September 1999. Luis Coelho provided <b>shared_ptr::swap</b> and <b>shared_array::swap</b></p>
|
||||
|
||||
<p>May 1999. In April and May, 1999, Valentin Bonnard and David Abrahams
|
||||
made a number of suggestions resulting in numerous improvements.</p>
|
||||
|
||||
<p>October 1998. In 1994 Greg Colvin proposed to the C++ Standards Committee
|
||||
classes named <b>auto_ptr</b> and <b>counted_ptr</b> which
|
||||
were very similar to what we now call <b>scoped_ptr</b> and <b>shared_ptr</b>.
|
||||
The committee document was 94-168/N0555, Exception Safe Smart Pointers. In
|
||||
one of the very few cases where the Library Working Group's recommendations were
|
||||
not followed by the full committee, <b>counted_ptr</b> was rejected
|
||||
and surprising transfer-of-ownership semantics were added to <b>auto_ptr</b>.</p>
|
||||
|
||||
<p>Beman Dawes proposed reviving the original semantics under the names <b>safe_ptr</b>
|
||||
and <b>counted_ptr</b> 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. During the discussion,
|
||||
the four class names were finalized, it was decided that there was no need to
|
||||
exactly follow the <b>std::auto_ptr</b> interface, and various
|
||||
function signatures and semantics were finalized.</p>
|
||||
|
||||
<p>Over the next three months, several implementations were considered for <b>shared_ptr</b>,
|
||||
and discussed on the <a href="http://www.boost.org">boost.org</a> mailing
|
||||
list. 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. 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. Kevlin Henney provided a paper he wrote on "Counted Body
|
||||
Techniques." 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 "parameterization will
|
||||
discourage users", and in the end we choose to supply only the direct
|
||||
implementation.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B %Y" startspan
|
||||
-->4 February 2002<!--webbot bot="Timestamp" endspan i-checksum="40737"
|
||||
--></p>
|
||||
|
||||
<p>Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler.
|
||||
Permission to copy, use,
|
||||
modify, sell and distribute this document is granted provided this copyright
|
||||
notice appears in all copies. This document is provided "as is"
|
||||
without express or implied warranty, and with no claim as to its suitability for
|
||||
any purpose.</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
295
smart_ptr_test.cpp
Normal file
295
smart_ptr_test.cpp
Normal file
@@ -0,0 +1,295 @@
|
||||
// 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.
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/shared_array.hpp>
|
||||
|
||||
#define BOOST_INCLUDE_MAIN
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
bool boost_error(char const *, char const *, char const *, long)
|
||||
{
|
||||
return true; // fail with assert()
|
||||
}
|
||||
|
||||
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\n";
|
||||
}
|
||||
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() << '\n';
|
||||
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 );
|
||||
|
||||
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) ) );
|
||||
|
||||
// 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 );
|
||||
|
||||
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) ) );
|
||||
|
||||
// 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\n";
|
||||
|
||||
new char[12345]; // deliberate memory leak to verify leaks detected
|
||||
|
||||
return 0;
|
||||
} // main
|
||||
|
BIN
smarttest.zip
Normal file
BIN
smarttest.zip
Normal file
Binary file not shown.
543
smarttests.htm
Normal file
543
smarttests.htm
Normal file
@@ -0,0 +1,543 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Smart Pointer Timings</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF">
|
||||
|
||||
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="middle" WIDTH="277" HEIGHT="86">Smart Pointer 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> </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"> </td>
|
||||
<td> </td>
|
||||
<td width="20"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20"> </td>
|
||||
<td><img src="msvcspeed.gif" width="560" height="355" alt="MSVC speed graph"></td>
|
||||
<td width="20"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20"> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><img src="gccspeed.gif" width="560" height="355" alt="GCC speed graph"></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20"> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p> </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> </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"> </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> </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> </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> </p>
|
||||
<h4 align="center">MSVC</h4>
|
||||
<table align="center" cellpadding="5" cellspacing="0" class="codetable" width="500">
|
||||
<tr>
|
||||
<th> </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> </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 = "outline"</li>
|
||||
</ul>
|
||||
<p> </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 "delete 0" 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> </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> </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 -->19 August 2001<!--webbot bot="Timestamp" endspan i-checksum="14767" -->
|
||||
</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 "as is" without express or implied warranty,
|
||||
and with no claim as to its suitability for any purpose.</p>
|
||||
</body>
|
||||
</html>
|
243
weak_ptr.htm
Normal file
243
weak_ptr.htm
Normal file
@@ -0,0 +1,243 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>weak_ptr</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
<body bgcolor="#ffffff" text="#000000">
|
||||
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="middle" width="277" height="86">weak_ptr
|
||||
class template</h1>
|
||||
<p>The <b>weak_ptr</b> class template stores a pointer to an object that's already
|
||||
managed by a <b>shared_ptr</b>. When the object last <b>shared_ptr</b> to the
|
||||
object goes away and the object is deleted, all <b>weak_ptr</b> objects have
|
||||
their stored pointers set to 0.</p>
|
||||
<p>Every <b>weak_ptr</b> meets the <b>CopyConstructible</b> and <b>Assignable</b> requirements
|
||||
of the C++ Standard Library, and so can be used in standard library containers.
|
||||
Comparison operators are supplied so that <b>weak_ptr</b> works with the
|
||||
standard library's associative containers.</p>
|
||||
<p>The class template is parameterized on <b>T</b>, the type of the object pointed
|
||||
to. <b>T</b> must meet the smart pointer <a href="smart_ptr.htm#Common requirements">
|
||||
common requirements</a>.</p>
|
||||
<P>Compared to <STRONG>shared_ptr</STRONG>, <STRONG>weak_ptr</STRONG> provides
|
||||
a very limited subset of operations since accessing its stored pointer is
|
||||
unsafe in multithreaded programs (that is, it may invoke undefined
|
||||
behavior.) Consider, for example, this innocent piece of code:</P>
|
||||
<pre>
|
||||
shared_ptr<int> p(new int(5));
|
||||
weak_ptr<int> q(p);
|
||||
|
||||
// some time later
|
||||
|
||||
if(int * r = q.get())
|
||||
{
|
||||
// use *r
|
||||
}
|
||||
</pre>
|
||||
<P>Imagine that after the <STRONG>if</STRONG>, but immediately before <STRONG>r</STRONG>
|
||||
is used, another thread executes the statement <code>p.reset()</code>. Now <STRONG>r</STRONG>
|
||||
is a dangling pointer.</P>
|
||||
<P>The solution to this problem is to create a temporary <STRONG>shared_ptr</STRONG>
|
||||
from <STRONG>q</STRONG>:</P>
|
||||
<pre>
|
||||
shared_ptr<int> p(new int(5));
|
||||
weak_ptr<int> q(p);
|
||||
|
||||
// some time later
|
||||
|
||||
if(shared_ptr<int> r = <a href="#make_shared">make_shared</a>(q))
|
||||
{
|
||||
// use *r
|
||||
}
|
||||
</pre>
|
||||
<p>Now <STRONG>r</STRONG> holds a reference to the object that was pointed by <STRONG>q</STRONG>.
|
||||
Even if <code>p.reset()</code> is executed in another thread, the object will
|
||||
stay alive until <STRONG>r</STRONG> goes out of scope (or is reset.)</p>
|
||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
||||
<pre>namespace boost {
|
||||
|
||||
template<typename T> class weak_ptr {
|
||||
|
||||
public:
|
||||
typedef T <a href="#element_type">element_type</a>;
|
||||
|
||||
<a href="#constructors">weak_ptr</a>();
|
||||
template<typename Y> <a href="#constructors">weak_ptr</a>(shared_ptr<Y> const & r); // never throws
|
||||
<a href="#destructor">~weak_ptr</a>(); // never throws
|
||||
|
||||
<a href="#constructors">weak_ptr</a>(weak_ptr const & r); // never throws
|
||||
template<typename Y> <a href="#constructors">weak_ptr</a>(weak_ptr<Y> const & r); // never throws
|
||||
|
||||
weak_ptr & <a href="#assignment">operator=</a>(weak_ptr const & r); // never throws
|
||||
template<typename Y> weak_ptr & <a href="#assignment">operator=</a>(weak_ptr<Y> const & r); // never throws
|
||||
template<typename Y> weak_ptr & <a href="#assignment">operator=</a>(shared_ptr<Y> const & r); // never throws
|
||||
|
||||
void <a href="#reset">reset</a>();
|
||||
T * <a href="#get">get</a>() const; // never throws; unsafe in multithreaded code!
|
||||
|
||||
long <a href="#use_count">use_count</a>() const; // never throws
|
||||
bool <a href="#expired">expired</a>() const; // never throws
|
||||
|
||||
void <a href="#swap">swap</a>(weak_ptr<T> & b); // never throws
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
bool <a href="#comparison">operator==</a>(weak_ptr<T> const & a, weak_ptr<U> const & b); // never throws
|
||||
template<typename T, typename U>
|
||||
bool <a href="#comparison">operator!=</a>(weak_ptr<T> const & a, weak_ptr<U> const & b); // never throws
|
||||
template<typename T>
|
||||
bool <a href="#comparison">operator<</a>(weak_ptr<T> const & a, weak_ptr<T> const & b); // never throws
|
||||
|
||||
template<typename T> void <a href="#free-swap">swap</a>(weak_ptr<T> & a, weak_ptr<T> & b); // never throws
|
||||
|
||||
template<typename T>
|
||||
shared_ptr<T> <a href="#make_shared">make_shared</a>(weak_ptr<T> const & r); // never throws
|
||||
|
||||
}
|
||||
</pre>
|
||||
<h2><a name="Members">Members</a></h2>
|
||||
<h3><a name="element_type">element_type</a></h3>
|
||||
<pre>typedef T element_type;</pre>
|
||||
<blockquote>
|
||||
<p>Provides the type of the template parameter T.</p>
|
||||
</blockquote>
|
||||
<h3><a name="constructors">constructors</a></h3>
|
||||
<pre>explicit weak_ptr();</pre>
|
||||
<blockquote>
|
||||
<p><b>Effects:</b> Constructs a <b>weak_ptr</b>.</p>
|
||||
<p><b>Postconditions:</b> <A href="#use_count">use count</A> is 0; the stored
|
||||
pointer is 0.</p>
|
||||
<p><b>Throws:</b> <b>std::bad_alloc</b>.</p>
|
||||
<p><b>Exception safety:</b> If an exception is thrown, the constructor has no
|
||||
effect.</p>
|
||||
<P><B>Notes:</B> <B>T</B> need not be a complete type. See the smart pointer <A href="smart_ptr.htm#Common requirements">
|
||||
common requirements</A>.</P>
|
||||
</blockquote>
|
||||
<pre>template<typename Y> weak_ptr</A>(shared_ptr<Y> const & r); // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Effects:</b> Constructs a <b>weak_ptr</b>, as if by storing a copy of the
|
||||
pointer stored in <b>r</b>.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> The <a href="#use_count">use count</a> for all copies is
|
||||
unchanged. When the last <b>shared_ptr</b> is destroyed, the use count and
|
||||
stored pointer become 0.</P>
|
||||
</blockquote>
|
||||
<pre>weak_ptr(weak_ptr const & r); // never throws
|
||||
template<typename Y> weak_ptr(weak_ptr<Y> const & r); // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Effects:</b> Constructs a <b>weak_ptr</b>, as if by storing a copy of the
|
||||
pointer stored in <b>r</b>.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> The <a href="#use_count">use count</a> for all copies is
|
||||
unchanged.</P>
|
||||
</blockquote>
|
||||
<h3><a name="destructor">destructor</a></h3>
|
||||
<pre>~weak_ptr(); // never throws</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Destroys this <b>weak_ptr</b> but has no effect on the object
|
||||
its stored pointer points to.</P>
|
||||
<P><B>Throws:</B> nothing.</P>
|
||||
<P><B>Notes:</B> <B>T</B> need not be a complete type. See the smart pointer <A href="smart_ptr.htm#Common requirements">
|
||||
common requirements</A>.</P>
|
||||
</BLOCKQUOTE>
|
||||
<h3><a name="assignment">assignment</a></h3>
|
||||
<pre>weak_ptr & <a href="#assignment">operator=</a>(weak_ptr const & r); // never throws
|
||||
template<typename Y> weak_ptr & <a href="#assignment">operator=</a>(weak_ptr<Y> const & r); // never throws
|
||||
template<typename Y> weak_ptr & <a href="#assignment">operator=</a>(shared_ptr<Y> const & r); // never throws</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Equivalent to <code>weak_ptr(r).swap(*this)</code>.</P>
|
||||
<P><B>Throws:</B> nothing.</P>
|
||||
<P><B>Notes:</B> The implementation is free to meet the effects (and the implied
|
||||
guarantees) via different means, without creating a temporary.</P>
|
||||
</BLOCKQUOTE>
|
||||
<h3><a name="reset">reset</a></h3>
|
||||
<pre>void reset();</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Equivalent to <code>weak_ptr().swap(*this)</code>.</P>
|
||||
</BLOCKQUOTE>
|
||||
<h3><a name="get">get</a></h3>
|
||||
<pre>T * get() const; // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> the stored pointer (0 if all <b>shared_ptr</b> objects for that
|
||||
pointer are destroyed.)</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> Using <b>get</b> in multithreaded code is dangerous. After the
|
||||
function returns, the pointed-to object may be destroyed by a different thread,
|
||||
since the <b>weak_ptr</b> doesn't affect its <b>use_count</b>.</P>
|
||||
</blockquote>
|
||||
<h3><a name="use_count">use_count</a></h3>
|
||||
<pre>long use_count() const; // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> the number of <b>shared_ptr</b> objects sharing ownership of the
|
||||
stored pointer.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> <code>use_count()</code> is not necessarily efficient. Use only
|
||||
for debugging and testing purposes, not for production code. <B>T</B> need not
|
||||
be a complete type. See the smart pointer <A href="smart_ptr.htm#Common requirements">
|
||||
common requirements</A>.</P>
|
||||
</blockquote>
|
||||
<h3><a name="expired">expired</a></h3>
|
||||
<pre>bool expired() const; // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> <code>use_count() == 0</code>.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> <code>expired()</code> may be faster than <code>use_count()</code>.
|
||||
<B>T</B> need not be a complete type. See the smart pointer <A href="smart_ptr.htm#Common requirements">
|
||||
common requirements</A>.</P>
|
||||
</blockquote>
|
||||
<h3><a name="swap">swap</a></h3>
|
||||
<pre>void swap(weak_ptr & b); // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Effects:</b> Exchanges the contents of the two smart pointers.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> <B>T</B> need not be a complete type. See the smart pointer <A href="smart_ptr.htm#Common requirements">
|
||||
common requirements</A>.</P>
|
||||
</blockquote>
|
||||
<h2><a name="functions">Free Functions</a></h2>
|
||||
<h3><a name="comparison">comparison</a></h3>
|
||||
<pre>template<typename T, typename U>
|
||||
bool operator==(weak_ptr<T> const & a, weak_ptr<U> const & b); // never throws
|
||||
template<typename T, typename U>
|
||||
bool operator!=(weak_ptr<T> const & a, weak_ptr<U> const & b); // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> <code>a.get() == b.get()</code>.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> <B>T</B> need not be a complete type. See the smart pointer <A href="smart_ptr.htm#Common requirements">
|
||||
common requirements</A>.</P>
|
||||
</blockquote>
|
||||
<pre>template<typename T>
|
||||
bool operator<(weak_ptr<T> const & a, weak_ptr<T> const & b); // never throws</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> an implementation-defined value such that <b>operator<</b> is
|
||||
a strict weak ordering as described in section 25.3 <code>[lib.alg.sorting]</code>
|
||||
of the C++ standard.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> Allows <STRONG>weak_ptr</STRONG> objects to be used as keys in
|
||||
associative containers. <B>T</B> need not be a complete type. See the smart
|
||||
pointer <A href="smart_ptr.htm#Common requirements">common requirements</A>.</P>
|
||||
</blockquote>
|
||||
<h3><a name="free-swap">swap</a></h3>
|
||||
<pre>template<typename T>
|
||||
void swap(weak_ptr<T> & a, weak_ptr<T> & b) // never throws</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Equivalent to <code>a.swap(b)</code>.</P>
|
||||
<P><B>Throws:</B> nothing.</P>
|
||||
<P><B>Notes:</B> Matches the interface of <B>std::swap</B>. Provided as an aid to
|
||||
generic programming.</P>
|
||||
</BLOCKQUOTE>
|
||||
<h3><a name="make_shared">make_shared</a></h3>
|
||||
<pre>template<typename T>
|
||||
shared_ptr<T> make_shared(weak_ptr<T> & const r) // never throws</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Returns:</B> <code>r.expired()? shared_ptr<T>(): shared_ptr<T>(r)</code>.</P>
|
||||
<P><B>Throws:</B> nothing.</P>
|
||||
</BLOCKQUOTE>
|
||||
<hr>
|
||||
<p>Revised 12 March 2002<!--webbot bot="Timestamp" i-checksum="38439" endspan --></p>
|
||||
<p>Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler.
|
||||
Copyright 2002 Peter Dimov. Permission to copy, use, modify, sell and
|
||||
distribute this document is granted provided this copyright notice appears in
|
||||
all copies. This document is provided "as is" without express or implied
|
||||
warranty, and with no claim as to its suitability for any purpose.</p>
|
||||
</A>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user