mirror of
https://github.com/boostorg/smart_ptr.git
synced 2025-10-04 19:51:02 +02:00
Compare commits
39 Commits
boost-1.28
...
boost-1.29
Author | SHA1 | Date | |
---|---|---|---|
|
9fa591db1f | ||
|
71a0c0ee97 | ||
|
4990c9c83e | ||
|
9dcbc46225 | ||
|
024f918b86 | ||
|
0f05f41306 | ||
|
4ea6decc7d | ||
|
f79b8cb7ae | ||
|
275cb77378 | ||
|
b916445dd8 | ||
|
c02fee7013 | ||
|
e77889679f | ||
|
b9dceb2340 | ||
|
e84eb3f1ba | ||
|
92999be436 | ||
|
bd4f575567 | ||
|
09016db3c3 | ||
|
c2ee5172b0 | ||
|
8436c4d271 | ||
|
a09c2e556f | ||
|
e650c7ff16 | ||
|
c06b4206f2 | ||
|
89435a6287 | ||
|
5328674c2d | ||
|
927fe73093 | ||
|
053aa108e3 | ||
|
b5e5c35696 | ||
|
77ad156c52 | ||
|
018c401e47 | ||
|
f586d3f83e | ||
|
3f0ebd4c71 | ||
|
33077bda71 | ||
|
547888d507 | ||
|
af6fe18c9d | ||
|
dca9628be3 | ||
|
d84fa738ef | ||
|
a322dc54dc | ||
|
951c2b7e83 | ||
|
23f68a5657 |
@@ -97,6 +97,8 @@ typedef long atomic_count;
|
||||
# include <boost/detail/atomic_count_pthreads.hpp>
|
||||
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
||||
# include <boost/detail/atomic_count_win32.hpp>
|
||||
#elif defined(__GLIBCPP__)
|
||||
# include <boost/detail/atomic_count_gcc.hpp>
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# define BOOST_AC_USE_PTHREADS
|
||||
# include <boost/detail/atomic_count_pthreads.hpp>
|
||||
|
61
include/boost/detail/atomic_count_gcc.hpp
Normal file
61
include/boost/detail/atomic_count_gcc.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef BOOST_DETAIL_ATOMIC_COUNT_GCC_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_ATOMIC_COUNT_GCC_HPP_INCLUDED
|
||||
|
||||
//
|
||||
// boost/detail/atomic_count_gcc.hpp
|
||||
//
|
||||
// atomic_count for GNU libstdc++ v3
|
||||
//
|
||||
// http://gcc.gnu.org/onlinedocs/porting/Thread-safety.html
|
||||
//
|
||||
// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd.
|
||||
// Copyright (c) 2002 Lars Gullik Bj<42>nnes <larsbj@lyx.org>
|
||||
//
|
||||
// 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 <bits/atomicity.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class atomic_count
|
||||
{
|
||||
public:
|
||||
|
||||
explicit atomic_count(long v) : value_(v) {}
|
||||
|
||||
void operator++()
|
||||
{
|
||||
__atomic_add(&value_, 1);
|
||||
}
|
||||
|
||||
long operator--()
|
||||
{
|
||||
return !__exchange_and_add(&value_, -1);
|
||||
}
|
||||
|
||||
operator long() const
|
||||
{
|
||||
return __exchange_and_add(&value_, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
atomic_count(atomic_count const &);
|
||||
atomic_count & operator=(atomic_count const &);
|
||||
|
||||
_Atomic_word value_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_ATOMIC_COUNT_GCC_HPP_INCLUDED
|
@@ -15,10 +15,10 @@
|
||||
// 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;
|
||||
// typedef <unspecified> 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
|
||||
// boost::detail::lightweight_mutex meets a subset of the Mutex concept
|
||||
// requirements: http://www.boost.org/libs/thread/doc/mutex_concept.html#Mutex
|
||||
//
|
||||
// * Used by the smart pointer library
|
||||
// * Performance oriented
|
||||
@@ -30,6 +30,23 @@
|
||||
// lightweight_mutex does not guarantee fairness.
|
||||
// * Never keep a lightweight_mutex locked for long periods.
|
||||
//
|
||||
// The current implementation can use a pthread_mutex, a CRITICAL_SECTION,
|
||||
// or a platform-specific spinlock.
|
||||
//
|
||||
// You can force a particular implementation by defining BOOST_LWM_USE_PTHREADS,
|
||||
// BOOST_LWM_USE_CRITICAL_SECTION, or BOOST_LWM_USE_SPINLOCK.
|
||||
//
|
||||
// If neither macro has been defined, the default is to use a spinlock on Win32,
|
||||
// and a pthread_mutex otherwise.
|
||||
//
|
||||
// Note that a spinlock is not a general synchronization primitive. In particular,
|
||||
// it is not guaranteed to be a memory barrier, and it is possible to "livelock"
|
||||
// if a lower-priority thread has acquired the spinlock but a higher-priority
|
||||
// thread is spinning trying to acquire the same lock.
|
||||
//
|
||||
// For these reasons, spinlocks have been disabled by default except on Windows,
|
||||
// where a spinlock can be several orders of magnitude faster than a CRITICAL_SECTION.
|
||||
|
||||
|
||||
// Note: lwm_linux.hpp has been disabled by default; see the comments
|
||||
// inside for more info.
|
||||
@@ -37,17 +54,19 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
//
|
||||
// Note to implementors: if you write a platform-specific lightweight_mutex
|
||||
// Note to implementors: if you write a platform-specific spinlock
|
||||
// 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
|
||||
// against the pthreads-based version using shared_ptr_timing_test.cpp and
|
||||
// shared_ptr_mt_test.cpp. Custom versions are usually not worth the trouble
|
||||
// _unless_ the performance gains are substantial.
|
||||
//
|
||||
// Be sure to compare against a "real" pthreads library;
|
||||
// shared_ptr_timing_test.cpp will compile succesfully with a stub do-nothing
|
||||
// pthreads library, since it doesn't create any threads.
|
||||
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
# include <boost/detail/lwm_nop.hpp>
|
||||
#elif defined(BOOST_USE_ASM_ATOMIC_H)
|
||||
#elif defined(BOOST_LWM_USE_SPINLOCK) && 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>
|
||||
@@ -55,8 +74,10 @@
|
||||
# include <boost/detail/lwm_pthreads.hpp>
|
||||
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
||||
# include <boost/detail/lwm_win32.hpp>
|
||||
#elif defined(__sgi)
|
||||
#elif defined(BOOST_LWM_USE_SPINLOCK) && defined(__sgi)
|
||||
# include <boost/detail/lwm_irix.hpp>
|
||||
#elif defined(BOOST_LWM_USE_SPINLOCK) && defined(__GLIBCPP__)
|
||||
# include <boost/detail/lwm_gcc.hpp>
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# define BOOST_LWM_USE_PTHREADS
|
||||
# include <boost/detail/lwm_pthreads.hpp>
|
||||
|
78
include/boost/detail/lwm_gcc.hpp
Normal file
78
include/boost/detail/lwm_gcc.hpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#ifndef BOOST_DETAIL_LWM_GCC_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_LWM_GCC_HPP_INCLUDED
|
||||
|
||||
//
|
||||
// boost/detail/lwm_gcc.hpp
|
||||
//
|
||||
// lightweight_mutex for GNU libstdc++ v3
|
||||
//
|
||||
// http://gcc.gnu.org/onlinedocs/porting/Thread-safety.html
|
||||
//
|
||||
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
|
||||
// Copyright (c) 2002 Lars Gullik Bj<42>nnes <larsbj@lyx.org>
|
||||
//
|
||||
// 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 <bits/atomicity.h>
|
||||
#include <sched.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class lightweight_mutex
|
||||
{
|
||||
private:
|
||||
|
||||
_Atomic_word a_;
|
||||
|
||||
lightweight_mutex(lightweight_mutex const &);
|
||||
lightweight_mutex & operator=(lightweight_mutex const &);
|
||||
|
||||
public:
|
||||
|
||||
lightweight_mutex(): a_(1)
|
||||
{
|
||||
}
|
||||
|
||||
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( !__exchange_and_add(&m_.a_, -1) )
|
||||
{
|
||||
__atomic_add(&m_.a_, 1);
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
~scoped_lock()
|
||||
{
|
||||
__atomic_add(&m_.a_, 1);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_LWM_GCC_HPP_INCLUDED
|
@@ -86,4 +86,4 @@ public:
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_DETAIL_LWM_LINUX_HPP_INCLUDED
|
||||
|
@@ -37,7 +37,14 @@ public:
|
||||
|
||||
lightweight_mutex()
|
||||
{
|
||||
|
||||
// HPUX 10.20 / DCE has a nonstandard pthread_mutex_init
|
||||
|
||||
#if defined(__hpux) && defined(_DECTHREADS_)
|
||||
pthread_mutex_init(&m_, pthread_mutexattr_default);
|
||||
#else
|
||||
pthread_mutex_init(&m_, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
~lightweight_mutex()
|
||||
|
@@ -18,6 +18,10 @@
|
||||
|
||||
#include <boost/detail/winapi.hpp>
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
# pragma warn -8027 // Functions containing while are not expanded inline
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
@@ -57,7 +61,12 @@ public:
|
||||
{
|
||||
while( winapi::InterlockedExchange(&m_.l_, 1) )
|
||||
{
|
||||
winapi::Sleep(0);
|
||||
// Note: changed to Sleep(1) from Sleep(0).
|
||||
// According to MSDN, Sleep(0) will never yield
|
||||
// to a lower-priority thread, whereas Sleep(1)
|
||||
// will. Performance seems not to be affected.
|
||||
|
||||
winapi::Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,8 +74,8 @@ public:
|
||||
{
|
||||
winapi::InterlockedExchange(&m_.l_, 0);
|
||||
|
||||
// Note: adding a Sleep(0) here will make
|
||||
// the mutex more fair and will increase the overall
|
||||
// Note: adding a yield here will make
|
||||
// the spinlock 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
|
||||
@@ -78,4 +87,8 @@ public:
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
# pragma warn .8027 // Functions containing while are not expanded inline
|
||||
#endif
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED
|
||||
|
@@ -17,11 +17,13 @@
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/checked_delete.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/detail/atomic_count.hpp>
|
||||
|
||||
#include <cstddef> // for std::ptrdiff_t
|
||||
#include <algorithm> // for std::swap
|
||||
#include <functional> // for std::less
|
||||
#include <cstddef> // for std::ptrdiff_t
|
||||
#include <algorithm> // for std::swap
|
||||
#include <functional> // for std::less
|
||||
#include <new> // for std::bad_alloc
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -38,22 +40,36 @@ public:
|
||||
|
||||
explicit shared_array(T * p = 0): px(p)
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
|
||||
try // prevent leak if new throws
|
||||
{
|
||||
pn = new count_type(1);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
checked_array_delete(p);
|
||||
boost::checked_array_delete(p);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
pn = new count_type(1);
|
||||
|
||||
if(pn == 0)
|
||||
{
|
||||
boost::checked_array_delete(p);
|
||||
boost::throw_exception(std::bad_alloc());
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
~shared_array()
|
||||
{
|
||||
if(--*pn == 0)
|
||||
{
|
||||
checked_array_delete(px);
|
||||
boost::checked_array_delete(px);
|
||||
delete pn;
|
||||
}
|
||||
}
|
||||
@@ -63,19 +79,19 @@ public:
|
||||
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;
|
||||
@@ -87,7 +103,7 @@ public:
|
||||
BOOST_ASSERT(i >= 0);
|
||||
return px[i];
|
||||
}
|
||||
|
||||
|
||||
long use_count() const // never throws
|
||||
{
|
||||
return *pn;
|
||||
@@ -97,15 +113,15 @@ public:
|
||||
{
|
||||
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
|
||||
|
||||
|
@@ -23,24 +23,46 @@
|
||||
#endif
|
||||
|
||||
#include <boost/checked_delete.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/detail/lightweight_mutex.hpp>
|
||||
|
||||
#include <functional> // for std::less
|
||||
#include <exception> // for std::exception
|
||||
#include <new> // for std::bad_alloc
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
# pragma warn -8026 // Functions with excep. spec. are not expanded inline
|
||||
# pragma warn -8027 // Functions containing try are not expanded inline
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
// The standard library that comes with Borland C++ 5.5.1
|
||||
// defines std::exception and its members as having C calling
|
||||
// convention (-pc). When the definition of use_count_is_zero
|
||||
// is compiled with -ps, the compiler issues an error.
|
||||
// Hence, the temporary #pragma option -pc below. The version
|
||||
// check is deliberately conservative.
|
||||
|
||||
#if defined(__BORLANDC__) && __BORLANDC__ == 0x551
|
||||
# pragma option push -pc
|
||||
#endif
|
||||
|
||||
class use_count_is_zero: public std::exception
|
||||
{
|
||||
public:
|
||||
|
||||
virtual char const * what() const throw()
|
||||
{
|
||||
return "use_count_is_zero";
|
||||
return "boost::use_count_is_zero";
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__BORLANDC__) && __BORLANDC__ == 0x551
|
||||
# pragma option pop
|
||||
#endif
|
||||
|
||||
class counted_base
|
||||
{
|
||||
private:
|
||||
@@ -50,14 +72,14 @@ private:
|
||||
public:
|
||||
|
||||
counted_base():
|
||||
use_count_(0), weak_count_(0), self_deleter_(&self_delete)
|
||||
use_count_(0), weak_count_(0)
|
||||
{
|
||||
}
|
||||
|
||||
// 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)
|
||||
use_count_(initial_use_count), weak_count_(initial_weak_count)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -78,12 +100,19 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// destruct() is called when weak_count_ drops to zero.
|
||||
|
||||
virtual void destruct() // nothrow
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
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();
|
||||
if(use_count_ == 0 && weak_count_ != 0) boost::throw_exception(boost::use_count_is_zero());
|
||||
++use_count_;
|
||||
++weak_count_;
|
||||
}
|
||||
@@ -108,9 +137,7 @@ public:
|
||||
|
||||
if(new_weak_count == 0)
|
||||
{
|
||||
// not a direct 'delete this', because the inlined
|
||||
// release() may use a different heap manager
|
||||
self_deleter_(this);
|
||||
destruct();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +162,7 @@ public:
|
||||
|
||||
if(new_weak_count == 0)
|
||||
{
|
||||
self_deleter_(this);
|
||||
destruct();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,19 +179,14 @@ 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)
|
||||
@@ -180,6 +202,13 @@ inline void intrusive_ptr_release(counted_base * p)
|
||||
namespace detail
|
||||
{
|
||||
|
||||
//
|
||||
// Borland's Codeguard trips up over the -Vx- option here:
|
||||
//
|
||||
#ifdef __CODEGUARD__
|
||||
#pragma option push -Vx-
|
||||
#endif
|
||||
|
||||
template<class P, class D> class counted_base_impl: public counted_base
|
||||
{
|
||||
private:
|
||||
@@ -230,6 +259,8 @@ public:
|
||||
|
||||
template<class P, class D> shared_count(P p, D d, void const * = 0): pi_(0)
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
|
||||
try
|
||||
{
|
||||
pi_ = new counted_base_impl<P, D>(p, d, 1, 1);
|
||||
@@ -239,6 +270,18 @@ public:
|
||||
d(p); // delete p
|
||||
throw;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
pi_ = new counted_base_impl<P, D>(p, d, 1, 1);
|
||||
|
||||
if(pi_ == 0)
|
||||
{
|
||||
d(p); // delete p
|
||||
boost::throw_exception(std::bad_alloc());
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class P, class D> shared_count(P, D, counted_base * pi): pi_(pi)
|
||||
@@ -308,6 +351,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __CODEGUARD__
|
||||
#pragma option pop
|
||||
#endif
|
||||
|
||||
|
||||
class weak_count
|
||||
{
|
||||
private:
|
||||
@@ -389,4 +437,9 @@ inline shared_count::shared_count(weak_count const & r): pi_(r.pi_)
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
# pragma warn .8027 // Functions containing try are not expanded inline
|
||||
# pragma warn .8026 // Functions with excep. spec. are not expanded inline
|
||||
#endif
|
||||
|
||||
#endif // #ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED
|
||||
|
@@ -17,14 +17,16 @@
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/checked_delete.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/detail/atomic_count.hpp>
|
||||
|
||||
#ifndef BOOST_NO_AUTO_PTR
|
||||
#include <memory> // for std::auto_ptr
|
||||
# include <memory> // for std::auto_ptr
|
||||
#endif
|
||||
|
||||
#include <algorithm> // for std::swap
|
||||
#include <functional> // for std::less
|
||||
#include <algorithm> // for std::swap
|
||||
#include <functional> // for std::less
|
||||
#include <new> // for std::bad_alloc
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -38,25 +40,40 @@ private:
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
typedef T value_type;
|
||||
|
||||
explicit shared_ptr(T * p = 0): px(p)
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
|
||||
try // prevent leak if new throws
|
||||
{
|
||||
pn = new count_type(1);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
checked_delete(p);
|
||||
boost::checked_delete(p);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
pn = new count_type(1);
|
||||
|
||||
if(pn == 0)
|
||||
{
|
||||
boost::checked_delete(p);
|
||||
boost::throw_exception(std::bad_alloc());
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
~shared_ptr()
|
||||
{
|
||||
if(--*pn == 0)
|
||||
{
|
||||
checked_delete(px);
|
||||
boost::checked_delete(px);
|
||||
delete pn;
|
||||
}
|
||||
}
|
||||
|
@@ -55,10 +55,41 @@ struct critical_section
|
||||
ulong_ptr_type SpinCount;
|
||||
};
|
||||
|
||||
#if defined(_WIN64)
|
||||
|
||||
// Intel 6.0 on Win64 version, posted by Tim Fenders to [boost-users]
|
||||
|
||||
extern "C" long_type __cdecl _InterlockedIncrement(long_type volatile *);
|
||||
extern "C" long_type __cdecl _InterlockedDecrement(long_type volatile *);
|
||||
extern "C" long_type __cdecl _InterlockedExchange(long_type volatile *, long_type);
|
||||
|
||||
#pragma intrinsic(_InterlockedIncrement)
|
||||
#pragma intrinsic(_InterlockedDecrement)
|
||||
#pragma intrinsic(_InterlockedExchange)
|
||||
|
||||
inline long_type InterlockedIncrement(long_type volatile * lp)
|
||||
{
|
||||
return _InterlockedIncrement(lp);
|
||||
}
|
||||
|
||||
inline long_type InterlockedDecrement(long_type volatile* lp)
|
||||
{
|
||||
return _InterlockedDecrement(lp);
|
||||
}
|
||||
|
||||
inline long_type InterlockedExchange(long_type volatile* lp, long_type l)
|
||||
{
|
||||
return _InterlockedExchange(lp, l);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
||||
extern "C" __declspec(dllimport) void __stdcall Sleep(dword_type);
|
||||
|
||||
extern "C" __declspec(dllimport) void __stdcall InitializeCriticalSection(critical_section *);
|
||||
|
@@ -61,7 +61,7 @@ public:
|
||||
if(p_ != 0) intrusive_ptr_release(p_);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES)
|
||||
|
||||
template<class U> intrusive_ptr(intrusive_ptr<U> const & rhs): p_(rhs.get())
|
||||
{
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
if(p_ != 0) intrusive_ptr_add_ref(p_);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES)
|
||||
|
||||
template<class U> intrusive_ptr & operator=(intrusive_ptr<U> const & rhs)
|
||||
{
|
||||
|
@@ -33,6 +33,8 @@ private:
|
||||
scoped_array(scoped_array const &);
|
||||
scoped_array & operator=(scoped_array const &);
|
||||
|
||||
typedef scoped_array<T> this_type;
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
@@ -67,6 +69,20 @@ public:
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// implicit conversion to "bool"
|
||||
|
||||
typedef T * (this_type::*unspecified_bool_type)() const;
|
||||
|
||||
operator unspecified_bool_type() const // never throws
|
||||
{
|
||||
return ptr == 0? 0: &this_type::get;
|
||||
}
|
||||
|
||||
bool operator! () const // never throws
|
||||
{
|
||||
return ptr == 0;
|
||||
}
|
||||
|
||||
void swap(scoped_array & b) // never throws
|
||||
{
|
||||
T * tmp = b.ptr;
|
||||
|
@@ -15,6 +15,10 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/checked_delete.hpp>
|
||||
|
||||
#ifndef BOOST_NO_AUTO_PTR
|
||||
# include <memory> // for std::auto_ptr
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
@@ -27,11 +31,13 @@ template<typename T> class scoped_ptr // noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
T* ptr;
|
||||
T * ptr;
|
||||
|
||||
scoped_ptr(scoped_ptr const &);
|
||||
scoped_ptr & operator=(scoped_ptr const &);
|
||||
|
||||
typedef scoped_ptr<T> this_type;
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
@@ -40,6 +46,14 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_AUTO_PTR
|
||||
|
||||
explicit scoped_ptr(std::auto_ptr<T> p): ptr(p.release()) // never throws
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
~scoped_ptr() // never throws
|
||||
{
|
||||
checked_delete(ptr);
|
||||
@@ -47,10 +61,9 @@ public:
|
||||
|
||||
void reset(T * p = 0) // never throws
|
||||
{
|
||||
if (ptr != p)
|
||||
if(ptr != p)
|
||||
{
|
||||
checked_delete(ptr);
|
||||
ptr = p;
|
||||
this_type(p).swap(*this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +84,20 @@ public:
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// implicit conversion to "bool"
|
||||
|
||||
typedef T * (this_type::*unspecified_bool_type)() const;
|
||||
|
||||
operator unspecified_bool_type() const // never throws
|
||||
{
|
||||
return ptr == 0? 0: &this_type::get;
|
||||
}
|
||||
|
||||
bool operator! () const // never throws
|
||||
{
|
||||
return ptr == 0;
|
||||
}
|
||||
|
||||
void swap(scoped_ptr & b) // never throws
|
||||
{
|
||||
T * tmp = b.ptr;
|
||||
@@ -84,6 +111,13 @@ template<typename T> inline void swap(scoped_ptr<T> & a, scoped_ptr<T> & b) // n
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
// get_pointer(p) is a generic way to say p.get()
|
||||
|
||||
template<typename T> inline T * get_pointer(scoped_ptr<T> const & p)
|
||||
{
|
||||
return p.get();
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_SCOPED_PTR_HPP_INCLUDED
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
#include <boost/config.hpp> // for broken compiler workarounds
|
||||
|
||||
#ifndef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
#if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES)
|
||||
#include <boost/detail/shared_array_nmt.hpp>
|
||||
#else
|
||||
|
||||
@@ -92,6 +92,20 @@ public:
|
||||
return px;
|
||||
}
|
||||
|
||||
// implicit conversion to "bool"
|
||||
|
||||
typedef T * (this_type::*unspecified_bool_type)() const;
|
||||
|
||||
operator unspecified_bool_type() const // never throws
|
||||
{
|
||||
return px == 0? 0: &this_type::get;
|
||||
}
|
||||
|
||||
bool operator! () const // never throws
|
||||
{
|
||||
return px == 0;
|
||||
}
|
||||
|
||||
bool unique() const // never throws
|
||||
{
|
||||
return pn.unique();
|
||||
@@ -137,6 +151,6 @@ template<typename T> void swap(shared_array<T> & a, shared_array<T> & b) // neve
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
#endif // #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES)
|
||||
|
||||
#endif // #ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED
|
||||
|
@@ -17,13 +17,13 @@
|
||||
|
||||
#include <boost/config.hpp> // for broken compiler workarounds
|
||||
|
||||
#ifndef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
#if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES)
|
||||
#include <boost/detail/shared_ptr_nmt.hpp>
|
||||
#else
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/checked_delete.hpp>
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/detail/shared_count.hpp>
|
||||
|
||||
#include <memory> // for std::auto_ptr
|
||||
@@ -56,6 +56,15 @@ template<> struct shared_ptr_traits<void>
|
||||
typedef void reference;
|
||||
};
|
||||
|
||||
#if !defined(BOOST_NO_CV_VOID_SPECIALIZATIONS)
|
||||
|
||||
template<> struct shared_ptr_traits<void const>
|
||||
{
|
||||
typedef void reference;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
@@ -81,6 +90,7 @@ private:
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
typedef T value_type;
|
||||
|
||||
shared_ptr(): px(0), pn()
|
||||
{
|
||||
@@ -137,7 +147,7 @@ public:
|
||||
{
|
||||
if (px == 0)
|
||||
{
|
||||
throw std::bad_cast();
|
||||
boost::throw_exception(std::bad_cast());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,6 +216,20 @@ public:
|
||||
return px;
|
||||
}
|
||||
|
||||
// implicit conversion to "bool"
|
||||
|
||||
typedef T * (this_type::*unspecified_bool_type)() const;
|
||||
|
||||
operator unspecified_bool_type() const // never throws
|
||||
{
|
||||
return px == 0? 0: &this_type::get;
|
||||
}
|
||||
|
||||
bool operator! () const // never throws
|
||||
{
|
||||
return px == 0;
|
||||
}
|
||||
|
||||
bool unique() const // never throws
|
||||
{
|
||||
return pn.unique();
|
||||
@@ -216,20 +240,6 @@ public:
|
||||
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);
|
||||
@@ -313,12 +323,34 @@ template<typename T> inline T * get_pointer(shared_ptr<T> const & p)
|
||||
return p.get();
|
||||
}
|
||||
|
||||
// shared_from_this() creates a shared_ptr from a raw pointer (usually 'this')
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
inline void sp_assert_counted_base(boost::counted_base const *)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T> inline T * sp_remove_const(T const * p)
|
||||
{
|
||||
return const_cast<T *>(p);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class T> shared_ptr<T> shared_from_this(T * p)
|
||||
{
|
||||
detail::sp_assert_counted_base(p);
|
||||
return shared_ptr<T>(detail::sp_remove_const(p));
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // #ifndef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
#endif // #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES)
|
||||
|
||||
#endif // #ifndef BOOST_SHARED_PTR_HPP_INCLUDED
|
||||
|
@@ -76,7 +76,7 @@ public:
|
||||
this_type().swap(*this);
|
||||
}
|
||||
|
||||
T * get() const // never throws; unsafe in multithreaded programs!
|
||||
T * get() const // never throws; deprecated, removal pending, don't use
|
||||
{
|
||||
return pn.use_count() == 0? 0: px;
|
||||
}
|
||||
@@ -168,6 +168,10 @@ template<class T> shared_ptr<T> make_shared(weak_ptr<T> const & r) // never thro
|
||||
}
|
||||
}
|
||||
|
||||
// Note: there is no get_pointer overload for weak_ptr.
|
||||
// This is intentional. Even get() will disappear in a
|
||||
// future release; these accessors are too error-prone.
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
|
212
scoped_array.htm
212
scoped_array.htm
@@ -1,53 +1,38 @@
|
||||
<!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 {
|
||||
<head>
|
||||
<title>scoped_array</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"><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> {
|
||||
|
||||
@@ -59,7 +44,7 @@ pointed to. <b>T</b> must meet the smart pointer
|
||||
|
||||
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="#operator[]">operator[]</a>(std::ptrdiff_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
|
||||
@@ -68,78 +53,59 @@ pointed to. <b>T</b> must meet the smart pointer
|
||||
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>
|
||||
|
||||
<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::ptrdiff_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>
|
||||
|
309
scoped_ptr.htm
309
scoped_ptr.htm
@@ -1,51 +1,38 @@
|
||||
<!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 {
|
||||
<head>
|
||||
<title>scoped_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"><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><STRONG>scoped_ptr</STRONG> cannot be used in C++ Standard Library containers.
|
||||
Use <a href="shared_ptr.htm"><b>shared_ptr</b></a> if you need a smart pointer
|
||||
that can.</p>
|
||||
<p><STRONG>scoped_ptr</STRONG> 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> {
|
||||
|
||||
@@ -53,7 +40,7 @@ pointed to. <b>T</b> must meet the smart pointer
|
||||
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
|
||||
<a href="#destructor">~scoped_ptr</a>(); // never throws
|
||||
|
||||
void <a href="#reset">reset</a>(T * p = 0); // never throws
|
||||
|
||||
@@ -67,75 +54,59 @@ pointed to. <b>T</b> must meet the smart pointer
|
||||
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>
|
||||
<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="destructor">destructor</a></h3>
|
||||
<pre>~scoped_ptr(); // never throws</pre>
|
||||
<p>Destroys the object pointed to by the stored pointer, if any, as if by using <tt>delete
|
||||
this->get()</tt>.</p>
|
||||
<P>
|
||||
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"; } };
|
||||
struct Shoe { ~Shoe() { std::cout << "Buckle my shoe\n"; } };
|
||||
|
||||
class MyClass {
|
||||
boost::scoped_ptr<int> ptr;
|
||||
@@ -151,67 +122,55 @@ void main()
|
||||
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
|
||||
</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>
|
||||
|
||||
</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>. When reading source code, it is valuable to be able to draw
|
||||
conclusions about program behavior based on the types being used. If <STRONG>scoped_ptr</STRONG>
|
||||
had a release() member, it would become possible to transfer ownership of the
|
||||
held pointer, weakening its role as a way of limiting resource lifetime to a
|
||||
given context. Use <STRONG>std::auto_ptr</STRONG> where transfer of ownership
|
||||
is required. (supplied by Dave Abrahams)</p>
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B %Y" startspan -->
|
||||
17 September 2002<!--webbot bot="Timestamp" endspan i-checksum="15110" --></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>
|
||||
|
313
shared_array.htm
313
shared_array.htm
@@ -1,47 +1,35 @@
|
||||
<!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 {
|
||||
<head>
|
||||
<title>shared_array</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">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 an object
|
||||
that has been allocated with the non-array form of <STRONG>new</STRONG>. See <a href="shared_ptr.htm">
|
||||
<b>shared_ptr</b></a> for that usage.</p>
|
||||
<p>Because the implementation uses reference counting, cycles of <b>shared_array</b>
|
||||
instances will not be reclaimed. 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 {
|
||||
|
||||
@@ -78,147 +66,114 @@ pointed to. <b>T</b> must meet the smart pointer
|
||||
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>
|
||||
<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::ptrdiff_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>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
310
shared_ptr.htm
310
shared_ptr.htm
@@ -8,18 +8,20 @@
|
||||
<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="#BestPractices">Best Practices</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="#ThreadSafety">Thread Safety</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>
|
||||
object, typically with a C++ <EM>new-expression</EM> . 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>
|
||||
@@ -27,11 +29,11 @@
|
||||
<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>
|
||||
<p>Because the implementation uses reference counting, cycles of <b>shared_ptr</b> instances
|
||||
will not be reclaimed. 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
|
||||
@@ -44,6 +46,43 @@
|
||||
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="BestPractices">Best Practices</a></h2>
|
||||
<P>A simple guideline that nearly eliminates the possibility of memory leaks
|
||||
is: always use a named smart pointer variable to hold the result of <STRONG>new. </STRONG>
|
||||
Every occurence of the <STRONG>new</STRONG> keyword in the code should have the
|
||||
form:</P>
|
||||
<PRE>shared_ptr<T> p(new Y);</PRE>
|
||||
<P>It is, of course, acceptable to use another smart pointer in place of <STRONG>shared_ptr</STRONG>
|
||||
above; having <STRONG>T</STRONG> and <STRONG>Y</STRONG> be the same type, or
|
||||
passing arguments to <STRONG>Y</STRONG>'s constructor is also OK.</P>
|
||||
<P>If you observe this guideline, it naturally follows that you will have no
|
||||
explicit <STRONG>delete</STRONG>s; <STRONG>try/catch</STRONG> constructs will
|
||||
be rare.</P>
|
||||
<P>Avoid using unnamed <STRONG>shared_ptr</STRONG> temporaries to save typing; to
|
||||
see why this is dangerous, consider this example:</P>
|
||||
<PRE>
|
||||
void f(shared_ptr<int>, int);
|
||||
int g();
|
||||
|
||||
void ok()
|
||||
{
|
||||
shared_ptr<int> p(new int(2));
|
||||
f(p, g());
|
||||
}
|
||||
|
||||
void bad()
|
||||
{
|
||||
f(shared_ptr<int>(new int(2)), g());
|
||||
}
|
||||
</PRE>
|
||||
<P>The function <STRONG>ok</STRONG> follows the guideline to the letter, whereas <STRONG>
|
||||
bad</STRONG> constructs the temporary <STRONG>shared_ptr</STRONG> in place,
|
||||
admitting the possibility of a memory leak. Since function arguments are
|
||||
evaluated in unspecified order, it is possible for <STRONG>new int(2)</STRONG> to
|
||||
be evaluated first, <STRONG>g()</STRONG> second, and we may never get to the <STRONG>
|
||||
shared_ptr </STRONG>constructor if <STRONG>g</STRONG> throws an exception.
|
||||
See <A href="http://www.gotw.ca/gotw/056.htm">Herb Sutter's treatment</A> of
|
||||
the issue for more information.</P>
|
||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
||||
<pre>namespace boost {
|
||||
|
||||
@@ -57,23 +96,23 @@
|
||||
|
||||
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);
|
||||
<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="#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);
|
||||
<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
|
||||
template<typename Y> explicit <A href="#constructors">shared_ptr</A>(<A href="weak_ptr.htm" >weak_ptr</A><Y> const & r);
|
||||
template<typename Y> explicit <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);
|
||||
void <A href="#reset" >reset</A>();
|
||||
template<typename Y> void <A href="#reset" >reset</A>(Y * p);
|
||||
template<typename Y, 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
|
||||
@@ -82,9 +121,9 @@
|
||||
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
|
||||
operator <a href="#conversions"><i>unspecified-bool-type</i></a>() const; // never throws
|
||||
|
||||
void <A href="#swap" >swap</A>(shared_ptr<T> & b); // never throws
|
||||
void <A href="#swap" >swap</A>(shared_ptr & b); // never throws
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
@@ -96,6 +135,8 @@
|
||||
|
||||
template<typename T> void <A href="#free-swap" >swap</A>(shared_ptr<T> & a, shared_ptr<T> & b); // never throws
|
||||
|
||||
template<typename T> T * <A href="#get_pointer" >get_pointer</A>(shared_ptr<T> const & p); // 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>
|
||||
@@ -106,6 +147,15 @@
|
||||
shared_ptr<T> <A href="#shared_polymorphic_downcast" >shared_polymorphic_downcast</A>(shared_ptr<U> const & r); // never throws
|
||||
|
||||
}</pre>
|
||||
<P><EM>[It might be convenient to relax the requirements on <STRONG>shared_ptr</STRONG>'s
|
||||
signature, allowing an additional, defaulted, template parameter; the parameter
|
||||
can encode the threading model, for example. This would help in detecting
|
||||
possible ODR violations.</EM></P>
|
||||
<P><EM> On the other hand, using <STRONG>shared_ptr</STRONG> as an argument to a
|
||||
template template parameter requires an exact signature match. </EM><EM>Metaprogramming
|
||||
experts tend to deemphasize template template parameters as they are too
|
||||
inflexible, but the alternative is typically an std::allocator::rebind-type
|
||||
"hack".]</EM></P>
|
||||
<h2><a name="Members">Members</a></h2>
|
||||
<h3><a name="element_type">element_type</a></h3>
|
||||
<pre>typedef T element_type;</pre>
|
||||
@@ -122,6 +172,22 @@
|
||||
<p><b>Exception safety:</b> If an exception is thrown, the constructor has no
|
||||
effect.</p>
|
||||
</blockquote>
|
||||
<P><EM>[The poscondition of use_count() == 1 is too strong. Having the nothrow
|
||||
guarantee is important, since <STRONG>reset()</STRONG> is specified in terms of
|
||||
the default constructor, but the current specification requires that a count be
|
||||
allocated. Therefore, this postcondition will be dropped in a future release.
|
||||
The use count of a default-constructed <STRONG>shared_ptr</STRONG>, including
|
||||
all copies created from it, will probably be left unspecified.</EM></P>
|
||||
<P><EM>There are two possible nothrow implementations, one stores 0 as a pointer to the
|
||||
reference count, the other uses a single statically allocated count for all
|
||||
default-constructed <STRONG>shared_ptr</STRONG>s. The second option is
|
||||
difficult to achieve in the current header-only reference implementation due to
|
||||
thread safety issues and initialization order, but it should not be precluded
|
||||
by the specification.</EM></P>
|
||||
<P><EM>A future release may enable <STRONG>shared_ptr</STRONG> construction from a
|
||||
literal zero, for consistency with built-in pointers. It is not clear yet
|
||||
whether this constructor should be left implicit, enabling <STRONG>0</STRONG> to
|
||||
be used as a shorthand for <STRONG>shared_ptr<T>().</STRONG>]</EM></P>
|
||||
<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>
|
||||
@@ -138,20 +204,67 @@
|
||||
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>
|
||||
<P><EM>[This constructor has been changed to a template in order to remember the actual
|
||||
pointer type passed. The destructor will call <STRONG>delete</STRONG> with the
|
||||
same pointer, complete with its original type, even when <STRONG>T</STRONG> does
|
||||
not have a virtual destructor, or is <STRONG>void</STRONG>.</EM></P>
|
||||
<P><EM>In the current implementation, if <STRONG>p</STRONG> is convertible to <STRONG>counted_base
|
||||
*</STRONG>, <STRONG>shared_ptr</STRONG> will use the embedded reference
|
||||
count supplied by <STRONG>counted_base</STRONG>. This is an (experimental)
|
||||
attempt to provide a way for <STRONG>shared_ptr</STRONG> to be constructed from
|
||||
a raw pointer such as <STRONG>this</STRONG>. A free function <STRONG>shared_from_this(q)</STRONG>
|
||||
performs the conversion when <STRONG>q</STRONG> is convertible to <STRONG>counted_base
|
||||
const *</STRONG>.</EM></P>
|
||||
<P><EM>The optional intrusive counting employed by the current implementation allows <STRONG>
|
||||
shared_ptr</STRONG> to interoperate with <STRONG>intrusive_ptr</STRONG>, an
|
||||
experimental generic intrusive-counted smart pointer.</EM></P>
|
||||
<P><EM> Another possible implementation is to use a global pointer-to-count map instead
|
||||
of intrusive counting. <STRONG>shared_from_this</STRONG> would no longer be
|
||||
O(1), which is a concern for some users, although I do not expect any
|
||||
performance problems, since the operation is rare. Maintaining a global
|
||||
map is difficult; it needs to be initialized before any <STRONG>shared_ptr</STRONG>
|
||||
instances are constructed, and the initialization needs to be thread safe.
|
||||
In addition, under the Windows dynamic library model, it is possible for
|
||||
several maps to exist.</EM></P>
|
||||
<P><EM> It is not yet clear which implementation should be used, or whether the
|
||||
specification should allow both; nevertheless, the ability to make a <STRONG>shared_ptr</STRONG>
|
||||
from <STRONG>this</STRONG> is considered essential by experienced smart
|
||||
pointer users.</EM><EM>]</EM></P>
|
||||
<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><b>Requirements:</b> <B>p</B> must be convertible to <B>T *</B>. <STRONG>D</STRONG>
|
||||
must be <STRONG>CopyConstructible</STRONG>. 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>
|
||||
<p><b>Notes:</b> When the the time comes to delete the object pointed to by <b>p</b>,
|
||||
the stored copy of <STRONG>d</STRONG> is invoked with the stored copy of <STRONG>p</STRONG>
|
||||
as an argument.</p>
|
||||
</blockquote>
|
||||
<P><EM>[Custom deallocators allow a factory function returning a <STRONG>shared_ptr</STRONG>
|
||||
to insulate the user from its memory allocation strategy. Since the deallocator
|
||||
is not part of the type, changing the allocation strategy does not break source
|
||||
or binary compatibility, and does not require a client recompilation. For
|
||||
example, a "no-op" deallocator is useful when returning a <STRONG>shared_ptr</STRONG>
|
||||
to a statically allocated object.</EM></P>
|
||||
<P><EM>The support for custom deallocators does not impose significant overhead. Other <STRONG>
|
||||
shared_ptr</STRONG> features still require a deallocator to be kept.</EM></P>
|
||||
<P><EM>The requirement that the copy constructor of <b>D</b> does not throw comes from
|
||||
the pass by value. If the copy constructor throws, the pointer is leaked.
|
||||
Removing the requirement requires a pass by (const) reference. The problems are
|
||||
that (1) pass by value conveniently changes functions (function references) to
|
||||
function pointers (this has to be performed manually otherwise and some
|
||||
compilers may not be able to do it) and (2) const references don't currently
|
||||
(per the standard) bind to functions. This can be solved (I think) but it
|
||||
requires an overload set that breaks on many compilers due to 14.5.5.2 problems
|
||||
(and of course it will break on compilers that don't do partial ordering at
|
||||
all.)</EM></P>
|
||||
<P><EM>The requrement will be removed when the aforementioned issues are
|
||||
resolved.]</EM></P>
|
||||
<pre>shared_ptr(shared_ptr const & r); // never throws
|
||||
template<typename Y> shared_ptr(shared_ptr<Y> const & r); // never throws</pre>
|
||||
<blockquote>
|
||||
@@ -161,7 +274,9 @@ template<typename Y> shared_ptr(shared_ptr<Y> const & r); // nev
|
||||
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>
|
||||
<P><EM>[The postcondition will be relaxed when a default-constructed <STRONG>shared_ptr</STRONG>
|
||||
is being copied.]</EM></P>
|
||||
<pre>template<typename Y> explicit shared_ptr(<A href="weak_ptr.htm">weak_ptr</A><Y> 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>
|
||||
@@ -171,15 +286,28 @@ template<typename Y> shared_ptr(shared_ptr<Y> const & r); // nev
|
||||
<p><b>Exception safety:</b> If an exception is thrown, the constructor has no
|
||||
effect.</p>
|
||||
</blockquote>
|
||||
<P><EM>[This constructor is an optional part of the specification; it depends on the
|
||||
existence of <STRONG>weak_ptr</STRONG>. It is true that <STRONG>weak_ptr</STRONG>
|
||||
support imposes overhead on every <STRONG>shared_ptr</STRONG> user, regardless
|
||||
of whether weak pointers are used.</EM></P>
|
||||
<P><EM>On the other hand, cyclic references are a serious problem with all reference
|
||||
counted designs. Not providing a solution within the library is unacceptable;
|
||||
if users are forced to reinvent the weak pointer wheel, there is substantial
|
||||
probability that they will get it wrong, as designing a safe <STRONG>weak_ptr</STRONG>
|
||||
interface is non-trivial.</EM></P>
|
||||
<P><EM>My opinion is that the added functionality is worth the cost. <STRONG>weak_ptr</STRONG>
|
||||
is provided in the reference implementation as a proof of concept.]</EM></P>
|
||||
<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>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, the constructor has no
|
||||
effect.</P>
|
||||
</BLOCKQUOTE>
|
||||
<P><EM>[This constructor takes a the source <STRONG>auto_ptr</STRONG> by reference and
|
||||
not by value, and cannot accept <STRONG>auto_ptr</STRONG> temporaries. This is
|
||||
by design, as the constructor offers the strong guarantee.]</EM></P>
|
||||
<h3><a name="destructor">destructor</a></h3>
|
||||
<pre>~shared_ptr(); // never throws</pre>
|
||||
<BLOCKQUOTE>
|
||||
@@ -195,9 +323,10 @@ template<typename Y> shared_ptr & operator=(shared_ptr<Y> const
|
||||
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>
|
||||
<P><B>Notes:</B> The use count updates caused by the temporary object construction
|
||||
and destruction are not considered observable side effects, and 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);
|
||||
@@ -206,11 +335,19 @@ q = p;
|
||||
</pre>
|
||||
<p>both assignments may be no-ops.</p>
|
||||
</BLOCKQUOTE>
|
||||
<P><EM>[Some experts consider the note to be redundant, as it appears to essentially
|
||||
mirror the "as if" rile. However, experience suggests that when C++ code is
|
||||
used to describe effects, it is often misinterpreted as required
|
||||
implementation. In addition, it is not entirely clear whether the "as if" rule
|
||||
actually applies here, so it's better to be explicit about the possible
|
||||
optimizations.]</EM></P>
|
||||
<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>
|
||||
<P><EM>[<STRONG>reset()</STRONG> will offer the nothrow guarantee in a future
|
||||
implementation.]</EM></P>
|
||||
<pre>template<typename Y> void reset(Y * p);</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Equivalent to <code>shared_ptr(p).swap(*this)</code>.</P>
|
||||
@@ -243,8 +380,12 @@ q = p;
|
||||
<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>
|
||||
<P><B>Notes:</B> <code>unique()</code> may be faster than <code>use_count()</code>.
|
||||
If you are using <code>unique()</code> to implement copy on write, do not rely
|
||||
on a specific value when the stored pointer is zero.</P>
|
||||
</blockquote>
|
||||
<P><EM>[In a future release, <STRONG>unique()</STRONG> will return an unspecified value
|
||||
for a default-constructed <STRONG>shared_ptr.</STRONG>]</EM></P>
|
||||
<h3><a name="use_count">use_count</a></h3>
|
||||
<pre>long use_count() const; // never throws</pre>
|
||||
<blockquote>
|
||||
@@ -255,16 +396,19 @@ q = p;
|
||||
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>
|
||||
<pre>operator <i>unspecified-bool-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>Returns:</b> an unspecified 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
|
||||
The actual target type is typically a pointer to a member function, avoiding
|
||||
many of the implicit conversion pitfalls.</P>
|
||||
</blockquote>
|
||||
<P><EM>[The conversion to bool is not merely syntactic sugar. It allows <STRONG>shared_ptr</STRONG>s
|
||||
to be declared in conditions when using <STRONG>shared_dynamic_cast </STRONG>or <STRONG>
|
||||
make_shared</STRONG>.]</EM></P>
|
||||
<h3><a name="swap">swap</a></h3>
|
||||
<pre>void swap(shared_ptr & b); // never throws</pre>
|
||||
<blockquote>
|
||||
@@ -288,22 +432,42 @@ q = p;
|
||||
<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>
|
||||
<p><b>Returns:</b> an unspecified 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>
|
||||
<P><EM>[<STRONG>Operator<</STRONG> has been preferred over a <STRONG>std::less </STRONG>
|
||||
specialization for consistency and legality reasons, as <STRONG>std::less</STRONG>
|
||||
is required to return the results of <STRONG>operator<</STRONG>, and many
|
||||
standard algorithms use <STRONG>operator<</STRONG> instead of <STRONG>std::less</STRONG>
|
||||
for comparisons when a predicate is not supplied. Composite objects, like <STRONG>std::pair</STRONG>,
|
||||
also implement their <STRONG>operator<</STRONG> in terms of their contained
|
||||
subobjects' <STRONG>operator<</STRONG>.</EM></P>
|
||||
<P><EM>The rest of the comparison operators are omitted by design.]</EM></P>
|
||||
<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>
|
||||
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>
|
||||
<P><EM>[<STRONG>swap</STRONG> is defined in the same namespace as <STRONG>shared_ptr</STRONG>
|
||||
as this is currently the only legal way to supply a <STRONG>swap</STRONG> function
|
||||
that has a chance to be used by the standard library.]</EM></P>
|
||||
<h3><a name="get_pointer">get_pointer</a></h3>
|
||||
<pre>template<typename T>
|
||||
T * get_pointer(shared_ptr<T> const & p); // never throws</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Returns:</B> <code>p.get()</code>.</P>
|
||||
<P><B>Throws:</B> nothing.</P>
|
||||
<P><B>Notes:</B> Provided as an aid to generic programming. Used by <A href="../bind/mem_fn.html">
|
||||
mem_fn</A>.</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>
|
||||
@@ -389,6 +553,65 @@ q = p;
|
||||
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="ThreadSafety">Thread Safety</a></h2>
|
||||
<p><STRONG>shared_ptr</STRONG> objects offer the same level of thread safety as
|
||||
built-in types. A <STRONG>shared_ptr</STRONG> instance can be "read"
|
||||
(accessed using only const operations) simultaneously by multiple threads.
|
||||
Different <STRONG>shared_ptr</STRONG> instances can be "written to" (accessed
|
||||
using mutable operations such as <STRONG>operator= </STRONG>or <STRONG>reset</STRONG>)
|
||||
simultaneosly by multiple threads (even when these instances are copies, and
|
||||
share the same reference count underneath.)</p>
|
||||
<P>Any other simultaneous accesses result in undefined behavior.</P>
|
||||
<P>Examples:</P>
|
||||
<pre>
|
||||
shared_ptr<int> p(new int(42));
|
||||
|
||||
//--- Example 1 ---
|
||||
|
||||
// thread A
|
||||
shared_ptr<int> p2(p); // reads p
|
||||
|
||||
// thread B
|
||||
shared_ptr<int> p3(p); // OK, multiple reads are safe
|
||||
|
||||
//--- Example 2 ---
|
||||
|
||||
// thread A
|
||||
|
||||
p.reset(new int(1912)); // writes p
|
||||
|
||||
// thread B
|
||||
p2.reset(); // OK, writes p2
|
||||
|
||||
//--- Example 3 ---
|
||||
|
||||
// thread A
|
||||
p = p3; // reads p3, writes p
|
||||
|
||||
// thread B
|
||||
p3.reset(); // writes p3; undefined, simultaneous read/write
|
||||
|
||||
//--- Example 4 ---
|
||||
|
||||
// thread A
|
||||
p3 = p2; // reads p2, writes p3
|
||||
|
||||
// thread B
|
||||
// p2 goes out of scope: undefined, the destructor is considered a "write access"
|
||||
|
||||
//--- Example 5 ---
|
||||
|
||||
// thread A
|
||||
p3.reset(new int(1));
|
||||
|
||||
// thread B
|
||||
p3.reset(new int(2)); // undefined, multiple writes
|
||||
</pre>
|
||||
<p><STRONG>shared_ptr</STRONG> uses <A href="../config/config.htm">Boost.Config</A>
|
||||
to detect whether the implementation supports threads. If your program is
|
||||
single-threaded, but your platform is autodetected by <STRONG>Boost.Config</STRONG>
|
||||
as supporting multiple threads, <STRONG>#define BOOST_DISABLE_THREADS</STRONG> to
|
||||
eliminate the thread safety overhead.</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
|
||||
@@ -408,8 +631,8 @@ q = p;
|
||||
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>
|
||||
<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>
|
||||
@@ -445,8 +668,7 @@ int * p = a.release();
|
||||
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>Revised $Date$</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
|
||||
|
@@ -19,9 +19,6 @@
|
||||
#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>
|
||||
@@ -153,7 +150,7 @@ int const m = 16; // threads
|
||||
char const * implementation = "spinlock";
|
||||
#endif
|
||||
|
||||
int test_main( int, char ** )
|
||||
int main()
|
||||
{
|
||||
std::printf("%s: %s, %d threads, %d iterations: ", title, implementation, m, n);
|
||||
|
||||
|
@@ -16,12 +16,13 @@
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
|
||||
#define BOOST_INCLUDE_MAIN
|
||||
#include <boost/test/test_tools.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
bool boost_error(char const *, char const *, char const *, long)
|
||||
{
|
||||
return true;
|
||||
@@ -112,6 +113,16 @@ public:
|
||||
std::cout << "Z(" << this << ")::~Z()\n";
|
||||
}
|
||||
|
||||
boost::shared_ptr<Z> shared_this()
|
||||
{
|
||||
return boost::shared_from_this(this);
|
||||
}
|
||||
|
||||
boost::shared_ptr<Z const> shared_this() const
|
||||
{
|
||||
return boost::shared_from_this(this);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Z(Z const &);
|
||||
@@ -178,11 +189,14 @@ template<class T> void test_is_zero(boost::shared_ptr<T> const & p)
|
||||
|
||||
template<class T> void test_is_nonzero(boost::shared_ptr<T> const & p)
|
||||
{
|
||||
BOOST_TEST(p);
|
||||
// p? true: false is used to test p in a boolean context.
|
||||
// BOOST_TEST(p) is not guaranteed to test the conversion,
|
||||
// as the macro might test !!p instead.
|
||||
BOOST_TEST(p? true: false);
|
||||
BOOST_TEST(p.get() != 0);
|
||||
}
|
||||
|
||||
int test_main(int, char * [])
|
||||
int main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
@@ -331,13 +345,28 @@ int test_main(int, char * [])
|
||||
|
||||
{
|
||||
// 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());
|
||||
|
||||
// test shared_from_this
|
||||
|
||||
boost::shared_ptr<Z> pz2 = pz->shared_this();
|
||||
|
||||
Z const & z = *pz2;
|
||||
|
||||
boost::shared_ptr<Z const> pz3 = z.shared_this();
|
||||
|
||||
BOOST_TEST(pz.use_count() == pz->use_count());
|
||||
BOOST_TEST(pz2.use_count() == pz2->use_count());
|
||||
BOOST_TEST(pz3.use_count() == pz3->use_count());
|
||||
BOOST_TEST(pz.use_count() == pz2.use_count());
|
||||
BOOST_TEST(pz.use_count() == pz3.use_count());
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_TEST(cnt == 0);
|
||||
|
||||
return 0;
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
367
smart_ptr.htm
367
smart_ptr.htm
@@ -1,207 +1,168 @@
|
||||
<!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"
|
||||
<head>
|
||||
<title>Smart Pointers</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">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>
|
||||
<P>Note that <STRONG>shared_ptr</STRONG> does not have this restriction, as most of
|
||||
its member functions do not require <STRONG>T</STRONG> to be a complete type.</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<>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>
|
||||
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>
|
||||
Embedded attached: the count is a member of the object pointed to.
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
@@ -18,8 +18,7 @@
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/shared_array.hpp>
|
||||
|
||||
#define BOOST_INCLUDE_MAIN
|
||||
#include <boost/test/test_tools.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
@@ -84,212 +83,214 @@ Incomplete * check_incomplete( shared_ptr<Incomplete>& incomplete,
|
||||
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 *[] ) {
|
||||
void test()
|
||||
{
|
||||
BOOST_TEST( UDT_use_count == 0 ); // reality check
|
||||
|
||||
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 );
|
||||
|
||||
// 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 = 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 );
|
||||
|
||||
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_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() );
|
||||
|
||||
// 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 );
|
||||
|
||||
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' );
|
||||
|
||||
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[0] = 'N';
|
||||
sa[4] = 'd';
|
||||
BOOST_TEST( strcmp( sap, "Not dog with mustard and relish" ) == 0 );
|
||||
sa.reset();
|
||||
BOOST_TEST( sa.get() == 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 );
|
||||
|
||||
// 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 );
|
||||
|
||||
*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 );
|
||||
|
||||
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 );
|
||||
|
||||
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) ) );
|
||||
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 );
|
||||
|
||||
// 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 );
|
||||
shared_ptr<int> cp4;
|
||||
swap( cp2, cp4 );
|
||||
BOOST_TEST( cp4.use_count() == 3 );
|
||||
BOOST_TEST( *cp4 == 87654 );
|
||||
BOOST_TEST( cp2.get() == 0 );
|
||||
|
||||
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 );
|
||||
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) ) );
|
||||
|
||||
BOOST_TEST( ca[0] == 'H' );
|
||||
BOOST_TEST( ca[30] == 'h' );
|
||||
|
||||
shared_array<char> ca2 ( ca );
|
||||
shared_array<char> ca3 ( ca2 );
|
||||
// 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 );
|
||||
|
||||
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 );
|
||||
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 );
|
||||
|
||||
ca.reset();
|
||||
BOOST_TEST( ca.get() == 0 );
|
||||
BOOST_TEST( ca[0] == 'H' );
|
||||
BOOST_TEST( ca[30] == 'h' );
|
||||
|
||||
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) ) );
|
||||
shared_array<char> ca2 ( ca );
|
||||
shared_array<char> ca3 ( ca2 );
|
||||
|
||||
// test shared_array with user defined type
|
||||
shared_array<UDT> udta ( new UDT[3] );
|
||||
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 );
|
||||
|
||||
udta[0].value( 111 );
|
||||
udta[1].value( 222 );
|
||||
udta[2].value( 333 );
|
||||
shared_array<UDT> udta2 ( udta );
|
||||
ca.reset();
|
||||
BOOST_TEST( ca.get() == 0 );
|
||||
|
||||
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 );
|
||||
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 );
|
||||
|
||||
BOOST_TEST( UDT_use_count == 4 ); // reality check
|
||||
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_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 );
|
||||
// test shared_array with user defined type
|
||||
shared_array<UDT> udta ( new UDT[3] );
|
||||
|
||||
sup->value( 54321 ) ;
|
||||
BOOST_TEST( sup->value() == 54321 );
|
||||
BOOST_TEST( up->value() == 54321 );
|
||||
udta[0].value( 111 );
|
||||
udta[1].value( 222 );
|
||||
udta[2].value( 333 );
|
||||
shared_array<UDT> udta2 ( udta );
|
||||
|
||||
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 );
|
||||
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 );
|
||||
|
||||
cout << "OK\n";
|
||||
BOOST_TEST( UDT_use_count == 4 ); // reality check
|
||||
|
||||
new char[12345]; // deliberate memory leak to verify leaks detected
|
||||
// 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 );
|
||||
|
||||
return 0;
|
||||
} // main
|
||||
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
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test();
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@
|
||||
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>,
|
||||
Gavin Collings,
|
||||
<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
|
||||
|
37
weak_ptr.htm
37
weak_ptr.htm
@@ -7,10 +7,15 @@
|
||||
<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>The <b>weak_ptr</b> class template stores a "weak reference" to an
|
||||
object that's already managed by a <b>shared_ptr</b>. To access the object, a <STRONG>
|
||||
weak_ptr</STRONG> can be converted to a <STRONG>shared_ptr</STRONG> using <A href="shared_ptr.htm#constructors">
|
||||
the <STRONG>shared_ptr</STRONG> constructor</A> or the function <STRONG><A href="#make_shared">
|
||||
make_shared</A></STRONG>. When the last <b>shared_ptr</b> to the object
|
||||
goes away and the object is deleted, the attempt to obtain a <STRONG>shared_ptr</STRONG>
|
||||
from the <b>weak_ptr</b> instances that refer to the deleted object will
|
||||
fail: the constructor will throw an exception of type <STRONG>boost::use_count_is_zero</STRONG>,
|
||||
and <STRONG>make_shared</STRONG> will return a default constructed (null) <STRONG>shared_ptr</STRONG>.</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
|
||||
@@ -20,8 +25,9 @@
|
||||
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>
|
||||
often dangerous in multithreaded programs, and sometimes unsafe even
|
||||
within a single thread (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);
|
||||
@@ -30,7 +36,7 @@ weak_ptr<int> q(p);
|
||||
|
||||
if(int * r = q.get())
|
||||
{
|
||||
// use *r
|
||||
// use *r
|
||||
}
|
||||
</pre>
|
||||
<P>Imagine that after the <STRONG>if</STRONG>, but immediately before <STRONG>r</STRONG>
|
||||
@@ -46,7 +52,7 @@ weak_ptr<int> q(p);
|
||||
|
||||
if(shared_ptr<int> r = <a href="#make_shared">make_shared</a>(q))
|
||||
{
|
||||
// use *r
|
||||
// use *r
|
||||
}
|
||||
</pre>
|
||||
<p>Now <STRONG>r</STRONG> holds a reference to the object that was pointed by <STRONG>q</STRONG>.
|
||||
@@ -72,7 +78,7 @@ if(shared_ptr<int> r = <a href="#make_shared">make_shared</a>(q))
|
||||
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!
|
||||
T * <a href="#get">get</a>() const; // never throws; deprecated, will disappear
|
||||
|
||||
long <a href="#use_count">use_count</a>() const; // never throws
|
||||
bool <a href="#expired">expired</a>() const; // never throws
|
||||
@@ -101,7 +107,7 @@ if(shared_ptr<int> r = <a href="#make_shared">make_shared</a>(q))
|
||||
<p>Provides the type of the template parameter T.</p>
|
||||
</blockquote>
|
||||
<h3><a name="constructors">constructors</a></h3>
|
||||
<pre>explicit weak_ptr();</pre>
|
||||
<pre> 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
|
||||
@@ -164,6 +170,11 @@ template<typename Y> weak_ptr & <a href="#assignment">operator=</a>(sh
|
||||
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>
|
||||
<P><EM>[<b>get</b> is very error-prone. Even single-threaded code may experience
|
||||
problems, as the returned pointer may be invalidated at any time, for example,
|
||||
indirectly by a member function of the pointee.</EM></P>
|
||||
<P><EM><STRONG>get</STRONG> is deprecated, and it will disappear in a future
|
||||
release. Do not use it.]</EM></P>
|
||||
<h3><a name="use_count">use_count</a></h3>
|
||||
<pre>long use_count() const; // never throws</pre>
|
||||
<blockquote>
|
||||
@@ -231,8 +242,12 @@ template<typename T, typename U>
|
||||
<P><B>Returns:</B> <code>r.expired()? shared_ptr<T>(): shared_ptr<T>(r)</code>.</P>
|
||||
<P><B>Throws:</B> nothing.</P>
|
||||
</BLOCKQUOTE>
|
||||
<P><EM>[The current implementation of <STRONG>make_shared</STRONG> can propagate
|
||||
an exception thrown by the <STRONG>shared_ptr</STRONG> default
|
||||
constructor, so it doesn't meet the stated requirements</EM><EM>. In a future
|
||||
release, this default constructor will not throw.]</EM></P>
|
||||
<hr>
|
||||
<p>Revised 12 March 2002<!--webbot bot="Timestamp" i-checksum="38439" endspan --></p>
|
||||
<p>Revised 29 August 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
|
||||
|
Reference in New Issue
Block a user