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