diff --git a/compatibility.htm b/compatibility.htm new file mode 100644 index 0000000..fb4d0a5 --- /dev/null +++ b/compatibility.htm @@ -0,0 +1,105 @@ + + + + + + +Smart Pointer Changes + + + + +

c++boost.gif (8819 bytes)Smart +Pointer Changes

+ +

The February 2002 change to the Boost smart pointers introduced a number +of changes. Since the previous version of the smart pointers was in use for +a long time, it's useful to have a detailed list of what changed from a library +user's point of view.

+ +

Note that for compilers that don't support member templates well enough, +a separate implementation is used that lacks many of the new features and is +more like the old version.

+ +

Features Requiring Code Changes to Take Advantage

+ + + +

Features That Improve Robustness

+ + + +

Implementation Details

+ + + +
+ +

Revised 1 February 2002

+ +

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.

+ + + + diff --git a/gccspeed.gif b/gccspeed.gif new file mode 100644 index 0000000..d78c06b Binary files /dev/null and b/gccspeed.gif differ diff --git a/include/boost/detail/atomic_count.hpp b/include/boost/detail/atomic_count.hpp new file mode 100644 index 0000000..2adb57e --- /dev/null +++ b/include/boost/detail/atomic_count.hpp @@ -0,0 +1,121 @@ +#ifndef BOOST_DETAIL_ATOMIC_COUNT_HPP_INCLUDED +#define BOOST_DETAIL_ATOMIC_COUNT_HPP_INCLUDED + +#if _MSC_VER >= 1020 +#pragma once +#endif + +// +// boost/detail/atomic_count.hpp - thread/SMP safe reference counter +// +// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// typedef boost::detail::atomic_count; +// +// atomic_count a(n); +// +// (n is convertible to long) +// +// Effects: Constructs an atomic_count with an initial value of n +// +// a; +// +// Returns: (long) the current value of a +// +// ++a; +// +// Effects: Atomically increments the value of a +// Returns: nothing +// +// --a; +// +// Effects: Atomically decrements the value of a +// Returns: (long) zero if the new value of a is zero, +// unspecified non-zero value otherwise (usually the new value) +// +// Important note: when --a returns zero, it must act as a +// read memory barrier (RMB); i.e. the calling thread must +// have a synchronized view of the memory +// +// On Intel IA-32 (x86) memory is always synchronized, so this +// is not a problem. +// +// On many architectures the atomic instructions already act as +// a memory barrier. +// +// This property is necessary for proper reference counting, since +// a thread can update the contents of a shared object, then +// release its reference, and another thread may immediately +// release the last reference causing object destruction. +// +// The destructor needs to have a synchronized view of the +// object to perform proper cleanup. +// +// Original example by Alexander Terekhov: +// +// Given: +// +// - a mutable shared object OBJ; +// - two threads THREAD1 and THREAD2 each holding +// a private smart_ptr object pointing to that OBJ. +// +// t1: THREAD1 updates OBJ (thread-safe via some synchronization) +// and a few cycles later (after "unlock") destroys smart_ptr; +// +// t2: THREAD2 destroys smart_ptr WITHOUT doing any synchronization +// with respect to shared mutable object OBJ; OBJ destructors +// are called driven by smart_ptr interface... +// + +// Note: atomic_count_linux.hpp has been disabled by default; see the +// comments inside for more info. + +#include + +#ifndef BOOST_HAS_THREADS + +namespace boost +{ + +namespace detail +{ + +typedef long atomic_count; + +} + +} + +#elif defined(BOOST_USE_ASM_ATOMIC_H) +# include +#elif defined(BOOST_AC_USE_PTHREADS) +# include +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +# include +#elif defined(BOOST_HAS_PTHREADS) +# define BOOST_AC_USE_PTHREADS +# include +#else + +// #warning Unrecognized platform, detail::atomic_count will not be thread safe + +namespace boost +{ + +namespace detail +{ + +typedef long atomic_count; + +} + +} + +#endif + +#endif // #ifndef BOOST_DETAIL_ATOMIC_COUNT_HPP_INCLUDED diff --git a/include/boost/detail/atomic_count_linux.hpp b/include/boost/detail/atomic_count_linux.hpp new file mode 100644 index 0000000..1a69cec --- /dev/null +++ b/include/boost/detail/atomic_count_linux.hpp @@ -0,0 +1,70 @@ +#ifndef BOOST_DETAIL_ATOMIC_COUNT_LINUX_HPP_INCLUDED +#define BOOST_DETAIL_ATOMIC_COUNT_LINUX_HPP_INCLUDED + +// +// boost/detail/atomic_count_linux.hpp +// +// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +// +// This implementation uses . This is a kernel header; +// using kernel headers in a user program may cause a number of problems, +// and not all flavors of Linux provide the atomic instructions. +// +// This file is only provided because the performance of this implementation +// is significantly higher than the pthreads version. Use at your own risk +// (by defining BOOST_USE_ASM_ATOMIC_H.) +// + +#include + +namespace boost +{ + +namespace detail +{ + +class atomic_count +{ +public: + + explicit atomic_count(long v) + { + atomic_t init = ATOMIC_INIT(v); + value_ = init; + } + + void operator++() + { + atomic_inc(&value_); + } + + long operator--() + { + return !atomic_dec_and_test(&value_); + } + + operator long() const + { + return atomic_read(&value_); + } + +private: + + atomic_count(atomic_count const &); + atomic_count & operator=(atomic_count const &); + + atomic_t value_; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_ATOMIC_COUNT_LINUX_HPP_INCLUDED diff --git a/include/boost/detail/atomic_count_pthreads.hpp b/include/boost/detail/atomic_count_pthreads.hpp new file mode 100644 index 0000000..0f8c663 --- /dev/null +++ b/include/boost/detail/atomic_count_pthreads.hpp @@ -0,0 +1,97 @@ +#ifndef BOOST_DETAIL_ATOMIC_COUNT_PTHREADS_HPP_INCLUDED +#define BOOST_DETAIL_ATOMIC_COUNT_PTHREADS_HPP_INCLUDED + +// +// boost/detail/atomic_count_pthreads.hpp +// +// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#include + +// +// The generic pthread_mutex-based implementation sometimes leads to +// inefficiencies. Example: a class with two atomic_count members +// can get away with a single mutex. +// +// Users can detect this situation by checking BOOST_AC_USE_PTHREADS. +// + +namespace boost +{ + +namespace detail +{ + +class atomic_count +{ +private: + + class scoped_lock + { + public: + + scoped_lock(pthread_mutex_t & m): m_(m) + { + pthread_mutex_lock(&m_); + } + + ~scoped_lock() + { + pthread_mutex_unlock(&m_); + } + + private: + + pthread_mutex_t & m_; + }; + +public: + + explicit atomic_count(long v): value_(v) + { + pthread_mutex_init(&mutex_, 0); + } + + ~atomic_count() + { + pthread_mutex_destroy(&mutex_); + } + + void operator++() + { + scoped_lock lock(mutex_); + ++value_; + } + + long operator--() + { + scoped_lock lock(mutex_); + return --value_; + } + + operator long() const + { + scoped_lock lock(mutex_); + return value_; + } + +private: + + atomic_count(atomic_count const &); + atomic_count & operator=(atomic_count const &); + + mutable pthread_mutex_t mutex_; + long value_; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_ATOMIC_COUNT_PTHREADS_HPP_INCLUDED diff --git a/include/boost/detail/atomic_count_win32.hpp b/include/boost/detail/atomic_count_win32.hpp new file mode 100644 index 0000000..0482757 --- /dev/null +++ b/include/boost/detail/atomic_count_win32.hpp @@ -0,0 +1,62 @@ +#ifndef BOOST_DETAIL_ATOMIC_COUNT_WIN32_HPP_INCLUDED +#define BOOST_DETAIL_ATOMIC_COUNT_WIN32_HPP_INCLUDED + +#if _MSC_VER >= 1020 +#pragma once +#endif + +// +// boost/detail/atomic_count_win32.hpp +// +// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#include + +namespace boost +{ + +namespace detail +{ + +class atomic_count +{ +public: + + explicit atomic_count(long v): value_(v) + { + } + + long operator++() + { + return winapi::InterlockedIncrement(&value_); + } + + long operator--() + { + return winapi::InterlockedDecrement(&value_); + } + + operator long() const + { + return value_; + } + +private: + + atomic_count(atomic_count const &); + atomic_count & operator=(atomic_count const &); + + volatile long value_; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_ATOMIC_COUNT_WIN32_HPP_INCLUDED diff --git a/include/boost/detail/lightweight_mutex.hpp b/include/boost/detail/lightweight_mutex.hpp new file mode 100644 index 0000000..6a74397 --- /dev/null +++ b/include/boost/detail/lightweight_mutex.hpp @@ -0,0 +1,67 @@ +#ifndef BOOST_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED +#define BOOST_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED + +#if _MSC_VER >= 1020 +#pragma once +#endif + +// +// boost/detail/lightweight_mutex.hpp - lightweight mutex +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// typedef boost::detail::lightweight_mutex; +// +// boost::detail::lightweight_mutex meets the Mutex concept requirements +// See http://www.boost.org/libs/thread/doc/mutex_concept.html#Mutex +// +// * Used by the smart pointer library +// * Performance oriented +// * Header-only implementation +// * Small memory footprint +// * Not a general purpose mutex, use boost::mutex, CRITICAL_SECTION or +// pthread_mutex instead. +// * Never spin in a tight lock/do-something/unlock loop, since +// lightweight_mutex does not guarantee fairness. +// * Never keep a lightweight_mutex locked for long periods. +// + +// Note: lwm_linux.hpp has been disabled by default; see the comments +// inside for more info. + + +#include + +// +// Note to implementors: if you write a platform-specific lightweight_mutex +// for a platform that supports pthreads, be sure to test its performance +// against the pthreads-based version using smart_ptr_timing_test.cpp and +// smart_ptr_mt_test.cpp. Custom versions are usually not worth the trouble +// _unless_ the performance gains are substantial. +// + +#ifndef BOOST_HAS_THREADS +# include +#elif defined(BOOST_USE_ASM_ATOMIC_H) +# include +#elif defined(BOOST_LWM_USE_CRITICAL_SECTION) +# include +#elif defined(BOOST_LWM_USE_PTHREADS) +# include +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +# include +#elif defined(__sgi) +# include +#elif defined(BOOST_HAS_PTHREADS) +# define BOOST_LWM_USE_PTHREADS +# include +#else +# include +#endif + +#endif // #ifndef BOOST_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED diff --git a/include/boost/detail/lwm_irix.hpp b/include/boost/detail/lwm_irix.hpp new file mode 100644 index 0000000..2a55161 --- /dev/null +++ b/include/boost/detail/lwm_irix.hpp @@ -0,0 +1,78 @@ +#ifndef BOOST_DETAIL_LWM_IRIX_HPP_INCLUDED +#define BOOST_DETAIL_LWM_IRIX_HPP_INCLUDED + +#if _MSC_VER >= 1020 +#pragma once +#endif + +// +// boost/detail/lwm_irix.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2002 Dan Gohman +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#include +#include +#include + +namespace boost +{ + +namespace detail +{ + +class lightweight_mutex +{ +private: + + __uint32_t l_; + + lightweight_mutex(lightweight_mutex const &); + lightweight_mutex & operator=(lightweight_mutex const &); + +public: + + lightweight_mutex(): l_(0) + { + } + + class scoped_lock; + friend class scoped_lock; + + class scoped_lock + { + private: + + lightweight_mutex & m_; + + scoped_lock(scoped_lock const &); + scoped_lock & operator=(scoped_lock const &); + + public: + + explicit scoped_lock(lightweight_mutex & m): m_(m) + { + while( test_and_set32(&m_.l_, 1) ) + { + sched_yield(); + } + } + + ~scoped_lock() + { + m_.l_ = 0; + } + }; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_LWM_IRIX_HPP_INCLUDED diff --git a/include/boost/detail/lwm_linux.hpp b/include/boost/detail/lwm_linux.hpp new file mode 100644 index 0000000..c4b3b1d --- /dev/null +++ b/include/boost/detail/lwm_linux.hpp @@ -0,0 +1,89 @@ +#ifndef BOOST_DETAIL_LWM_LINUX_HPP_INCLUDED +#define BOOST_DETAIL_LWM_LINUX_HPP_INCLUDED + +#if _MSC_VER >= 1020 +#pragma once +#endif + +// +// boost/detail/lwm_linux.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +// +// This implementation uses . This is a kernel header; +// using kernel headers in a user program may cause a number of problems, +// and not all flavors of Linux provide the atomic instructions. +// +// This file is only provided because the performance of this implementation +// is about 3.5 times higher than the pthreads version. Use at your own risk +// (by defining BOOST_USE_ASM_ATOMIC_H.) +// + +#include +#include + +namespace boost +{ + +namespace detail +{ + +class lightweight_mutex +{ +private: + + atomic_t a_; + + lightweight_mutex(lightweight_mutex const &); + lightweight_mutex & operator=(lightweight_mutex const &); + +public: + + lightweight_mutex() + { + atomic_t a = ATOMIC_INIT(1); + a_ = a; + } + + class scoped_lock; + friend class scoped_lock; + + class scoped_lock + { + private: + + lightweight_mutex & m_; + + scoped_lock(scoped_lock const &); + scoped_lock & operator=(scoped_lock const &); + + public: + + explicit scoped_lock(lightweight_mutex & m): m_(m) + { + while( !atomic_dec_and_test(&m_.a_) ) + { + atomic_inc(&m_.a_); + sched_yield(); + } + } + + ~scoped_lock() + { + atomic_inc(&m_.a_); + } + }; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED diff --git a/include/boost/detail/lwm_nop.hpp b/include/boost/detail/lwm_nop.hpp new file mode 100644 index 0000000..671a5b0 --- /dev/null +++ b/include/boost/detail/lwm_nop.hpp @@ -0,0 +1,36 @@ +#ifndef BOOST_DETAIL_LWM_NOP_HPP_INCLUDED +#define BOOST_DETAIL_LWM_NOP_HPP_INCLUDED + +#if _MSC_VER >= 1020 +#pragma once +#endif + +// +// boost/detail/lwm_nop.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +namespace boost +{ + +namespace detail +{ + +class lightweight_mutex +{ +public: + + typedef lightweight_mutex scoped_lock; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_LWM_NOP_HPP_INCLUDED diff --git a/include/boost/detail/lwm_pthreads.hpp b/include/boost/detail/lwm_pthreads.hpp new file mode 100644 index 0000000..ba8d762 --- /dev/null +++ b/include/boost/detail/lwm_pthreads.hpp @@ -0,0 +1,78 @@ +#ifndef BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED +#define BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED + +#if _MSC_VER >= 1020 +#pragma once +#endif + +// +// boost/detail/lwm_pthreads.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#include + +namespace boost +{ + +namespace detail +{ + +class lightweight_mutex +{ +private: + + pthread_mutex_t m_; + + lightweight_mutex(lightweight_mutex const &); + lightweight_mutex & operator=(lightweight_mutex const &); + +public: + + lightweight_mutex() + { + pthread_mutex_init(&m_, 0); + } + + ~lightweight_mutex() + { + pthread_mutex_destroy(&m_); + } + + class scoped_lock; + friend class scoped_lock; + + class scoped_lock + { + private: + + pthread_mutex_t & m_; + + scoped_lock(scoped_lock const &); + scoped_lock & operator=(scoped_lock const &); + + public: + + scoped_lock(lightweight_mutex & m): m_(m.m_) + { + pthread_mutex_lock(&m_); + } + + ~scoped_lock() + { + pthread_mutex_unlock(&m_); + } + }; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED diff --git a/include/boost/detail/lwm_win32.hpp b/include/boost/detail/lwm_win32.hpp new file mode 100644 index 0000000..a54aefc --- /dev/null +++ b/include/boost/detail/lwm_win32.hpp @@ -0,0 +1,81 @@ +#ifndef BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED +#define BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED + +#if _MSC_VER >= 1020 +#pragma once +#endif + +// +// boost/detail/lwm_win32.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#include + +namespace boost +{ + +namespace detail +{ + +class lightweight_mutex +{ +private: + + long l_; + + lightweight_mutex(lightweight_mutex const &); + lightweight_mutex & operator=(lightweight_mutex const &); + +public: + + lightweight_mutex(): l_(0) + { + } + + class scoped_lock; + friend class scoped_lock; + + class scoped_lock + { + private: + + lightweight_mutex & m_; + + scoped_lock(scoped_lock const &); + scoped_lock & operator=(scoped_lock const &); + + public: + + explicit scoped_lock(lightweight_mutex & m): m_(m) + { + while( winapi::InterlockedExchange(&m_.l_, 1) ) + { + winapi::Sleep(0); + } + } + + ~scoped_lock() + { + winapi::InterlockedExchange(&m_.l_, 0); + + // Note: adding a Sleep(0) here will make + // the mutex more fair and will increase the overall + // performance of some applications substantially in + // high contention situations, but will penalize the + // low contention / single thread case up to 5x + } + }; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED diff --git a/include/boost/detail/lwm_win32_cs.hpp b/include/boost/detail/lwm_win32_cs.hpp new file mode 100644 index 0000000..3127004 --- /dev/null +++ b/include/boost/detail/lwm_win32_cs.hpp @@ -0,0 +1,78 @@ +#ifndef BOOST_DETAIL_LWM_WIN32_CS_HPP_INCLUDED +#define BOOST_DETAIL_LWM_WIN32_CS_HPP_INCLUDED + +#if _MSC_VER >= 1020 +#pragma once +#endif + +// +// boost/detail/lwm_win32_cs.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#include + +namespace boost +{ + +namespace detail +{ + +class lightweight_mutex +{ +private: + + winapi::critical_section cs_; + + lightweight_mutex(lightweight_mutex const &); + lightweight_mutex & operator=(lightweight_mutex const &); + +public: + + lightweight_mutex() + { + winapi::InitializeCriticalSection(&cs_); + } + + ~lightweight_mutex() + { + winapi::DeleteCriticalSection(&cs_); + } + + class scoped_lock; + friend class scoped_lock; + + class scoped_lock + { + private: + + lightweight_mutex & m_; + + scoped_lock(scoped_lock const &); + scoped_lock & operator=(scoped_lock const &); + + public: + + explicit scoped_lock(lightweight_mutex & m): m_(m) + { + winapi::EnterCriticalSection(&m_.cs_); + } + + ~scoped_lock() + { + winapi::LeaveCriticalSection(&m_.cs_); + } + }; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_LWM_WIN32_CS_HPP_INCLUDED diff --git a/include/boost/detail/shared_array_nmt.hpp b/include/boost/detail/shared_array_nmt.hpp new file mode 100644 index 0000000..3ff1954 --- /dev/null +++ b/include/boost/detail/shared_array_nmt.hpp @@ -0,0 +1,136 @@ +#ifndef BOOST_DETAIL_SHARED_ARRAY_NMT_HPP_INCLUDED +#define BOOST_DETAIL_SHARED_ARRAY_NMT_HPP_INCLUDED + +// +// detail/shared_array_nmt.hpp - shared_array.hpp without member templates +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/shared_array.htm for documentation. +// + +#include +#include +#include + +#include // for std::ptrdiff_t +#include // for std::swap +#include // for std::less + +namespace boost +{ + +template class shared_array +{ +private: + + typedef detail::atomic_count count_type; + +public: + + typedef T element_type; + + explicit shared_array(T * p = 0): px(p) + { + try // prevent leak if new throws + { + pn = new count_type(1); + } + catch(...) + { + checked_array_delete(p); + throw; + } + } + + ~shared_array() + { + if(--*pn == 0) + { + checked_array_delete(px); + delete pn; + } + } + + shared_array(shared_array const & r) : px(r.px) // never throws + { + pn = r.pn; + ++*pn; + } + + shared_array & operator=(shared_array const & r) + { + shared_array(r).swap(*this); + return *this; + } + + void reset(T * p = 0) + { + BOOST_ASSERT(p == 0 || p != px); + shared_array(p).swap(*this); + } + + T * get() const // never throws + { + return px; + } + + T & operator[](std::ptrdiff_t i) const // never throws + { + BOOST_ASSERT(px != 0); + BOOST_ASSERT(i >= 0); + return px[i]; + } + + long use_count() const // never throws + { + return *pn; + } + + bool unique() const // never throws + { + return *pn == 1; + } + + void swap(shared_array & other) // never throws + { + std::swap(px, other.px); + std::swap(pn, other.pn); + } + +private: + + T * px; // contained pointer + count_type * pn; // ptr to reference counter + +}; // shared_array + +template inline bool operator==(shared_array const & a, shared_array const & b) +{ + return a.get() == b.get(); +} + +template inline bool operator!=(shared_array const & a, shared_array const & b) +{ + return a.get() != b.get(); +} + +template inline bool operator<(shared_array const & a, shared_array const & b) +{ + return std::less()(a.get(), b.get()); +} + +template void swap(shared_array & a, shared_array & b) +{ + a.swap(b); +} + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_SHARED_ARRAY_NMT_HPP_INCLUDED diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp new file mode 100644 index 0000000..63316f4 --- /dev/null +++ b/include/boost/detail/shared_count.hpp @@ -0,0 +1,392 @@ +#ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED +#define BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED + +#if _MSC_VER >= 1020 +#pragma once +#endif + +// +// detail/shared_count.hpp +// +// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#include + +#ifndef BOOST_NO_AUTO_PTR +# include +#endif + +#include +#include + +#include // for std::less +#include // for std::exception + +namespace boost +{ + +class use_count_is_zero: public std::exception +{ +public: + + virtual char const * what() const throw() + { + return "use_count_is_zero"; + } +}; + +class counted_base +{ +private: + + typedef detail::lightweight_mutex mutex_type; + +public: + + counted_base(): + use_count_(0), weak_count_(0), self_deleter_(&self_delete) + { + } + + // pre: initial_use_count <= initial_weak_count + + explicit counted_base(long initial_use_count, long initial_weak_count): + use_count_(initial_use_count), weak_count_(initial_weak_count), self_deleter_(&self_delete) + { + } + + virtual ~counted_base() // nothrow + { + } + + // dispose() is called when use_count_ drops to zero, to release + // the resources managed by *this. + // + // counted_base doesn't manage any resources except itself, and + // the default implementation is a no-op. + // + // dispose() is not pure virtual since weak_ptr instantiates a + // counted_base in its default constructor. + + virtual void dispose() // nothrow + { + } + + void add_ref() + { +#ifdef BOOST_HAS_THREADS + mutex_type::scoped_lock lock(mtx_); +#endif + if(use_count_ == 0 && weak_count_ != 0) throw use_count_is_zero(); + ++use_count_; + ++weak_count_; + } + + void release() // nothrow + { + long new_use_count; + long new_weak_count; + + { +#ifdef BOOST_HAS_THREADS + mutex_type::scoped_lock lock(mtx_); +#endif + new_use_count = --use_count_; + new_weak_count = --weak_count_; + } + + if(new_use_count == 0) + { + dispose(); + } + + if(new_weak_count == 0) + { + // not a direct 'delete this', because the inlined + // release() may use a different heap manager + self_deleter_(this); + } + } + + void weak_add_ref() // nothrow + { +#ifdef BOOST_HAS_THREADS + mutex_type::scoped_lock lock(mtx_); +#endif + ++weak_count_; + } + + void weak_release() // nothrow + { + long new_weak_count; + + { +#ifdef BOOST_HAS_THREADS + mutex_type::scoped_lock lock(mtx_); +#endif + new_weak_count = --weak_count_; + } + + if(new_weak_count == 0) + { + self_deleter_(this); + } + } + + long use_count() const // nothrow + { +#ifdef BOOST_HAS_THREADS + mutex_type::scoped_lock lock(mtx_); +#endif + return use_count_; + } + +private: + + counted_base(counted_base const &); + counted_base & operator= (counted_base const &); + + static void self_delete(counted_base * p) + { + delete p; + } + + // inv: use_count_ <= weak_count_ + + long use_count_; + long weak_count_; +#ifdef BOOST_HAS_THREADS + mutable mutex_type mtx_; +#endif + void (*self_deleter_) (counted_base *); +}; + +inline void intrusive_ptr_add_ref(counted_base * p) +{ + p->add_ref(); +} + +inline void intrusive_ptr_release(counted_base * p) +{ + p->release(); +} + +namespace detail +{ + +template class counted_base_impl: public counted_base +{ +private: + + P ptr; // copy constructor must not throw + D del; // copy constructor must not throw + + counted_base_impl(counted_base_impl const &); + counted_base_impl & operator= (counted_base_impl const &); + +public: + + // pre: initial_use_count <= initial_weak_count, d(p) must not throw + + counted_base_impl(P p, D d, long initial_use_count, long initial_weak_count): + counted_base(initial_use_count, initial_weak_count), ptr(p), del(d) + { + } + + virtual void dispose() // nothrow + { + del(ptr); + } +}; + +class weak_count; + +class shared_count +{ +private: + + counted_base * pi_; + + friend class weak_count; + + template shared_count(P, D, counted_base const *); + +public: + + shared_count(): pi_(new counted_base(1, 1)) + { + } + + explicit shared_count(counted_base * pi): pi_(pi) // never throws + { + pi_->add_ref(); + } + + template shared_count(P p, D d, void const * = 0): pi_(0) + { + try + { + pi_ = new counted_base_impl(p, d, 1, 1); + } + catch(...) + { + d(p); // delete p + throw; + } + } + + template shared_count(P, D, counted_base * pi): pi_(pi) + { + pi_->add_ref(); + } + +#ifndef BOOST_NO_AUTO_PTR + + // auto_ptr is special cased to provide the strong guarantee + + template + explicit shared_count(std::auto_ptr & r): pi_(new counted_base_impl< Y *, checked_deleter >(r.get(), checked_deleter(), 1, 1)) + { + r.release(); + } + +#endif + + ~shared_count() // nothrow + { + pi_->release(); + } + + shared_count(shared_count const & r): pi_(r.pi_) // nothrow + { + pi_->add_ref(); + } + + explicit shared_count(weak_count const & r); // throws use_count_is_zero when r.use_count() == 0 + + shared_count & operator= (shared_count const & r) // nothrow + { + counted_base * tmp = r.pi_; + tmp->add_ref(); + pi_->release(); + pi_ = tmp; + + return *this; + } + + void swap(shared_count & r) // nothrow + { + counted_base * tmp = r.pi_; + r.pi_ = pi_; + pi_ = tmp; + } + + long use_count() const // nothrow + { + return pi_->use_count(); + } + + bool unique() const // nothrow + { + return pi_->use_count() == 1; + } + + friend inline bool operator==(shared_count const & a, shared_count const & b) + { + return a.pi_ == b.pi_; + } + + friend inline bool operator<(shared_count const & a, shared_count const & b) + { + return std::less()(a.pi_, b.pi_); + } +}; + +class weak_count +{ +private: + + counted_base * pi_; + + friend class shared_count; + +public: + + weak_count(): pi_(new counted_base(0, 1)) // can throw + { + } + + weak_count(shared_count const & r): pi_(r.pi_) // nothrow + { + pi_->weak_add_ref(); + } + + weak_count(weak_count const & r): pi_(r.pi_) // nothrow + { + pi_->weak_add_ref(); + } + + ~weak_count() // nothrow + { + pi_->weak_release(); + } + + weak_count & operator= (shared_count const & r) // nothrow + { + counted_base * tmp = r.pi_; + tmp->weak_add_ref(); + pi_->weak_release(); + pi_ = tmp; + + return *this; + } + + weak_count & operator= (weak_count const & r) // nothrow + { + counted_base * tmp = r.pi_; + tmp->weak_add_ref(); + pi_->weak_release(); + pi_ = tmp; + + return *this; + } + + void swap(weak_count & r) // nothrow + { + counted_base * tmp = r.pi_; + r.pi_ = pi_; + pi_ = tmp; + } + + long use_count() const // nothrow + { + return pi_->use_count(); + } + + friend inline bool operator==(weak_count const & a, weak_count const & b) + { + return a.pi_ == b.pi_; + } + + friend inline bool operator<(weak_count const & a, weak_count const & b) + { + return std::less()(a.pi_, b.pi_); + } +}; + +inline shared_count::shared_count(weak_count const & r): pi_(r.pi_) +{ + pi_->add_ref(); +} + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED diff --git a/include/boost/detail/shared_ptr_nmt.hpp b/include/boost/detail/shared_ptr_nmt.hpp new file mode 100644 index 0000000..79d5b5d --- /dev/null +++ b/include/boost/detail/shared_ptr_nmt.hpp @@ -0,0 +1,166 @@ +#ifndef BOOST_DETAIL_SHARED_PTR_NMT_HPP_INCLUDED +#define BOOST_DETAIL_SHARED_PTR_NMT_HPP_INCLUDED + +// +// detail/shared_ptr_nmt.hpp - shared_ptr.hpp without member templates +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. +// + +#include +#include +#include + +#ifndef BOOST_NO_AUTO_PTR +#include // for std::auto_ptr +#endif + +#include // for std::swap +#include // for std::less + +namespace boost +{ + +template class shared_ptr +{ +private: + + typedef detail::atomic_count count_type; + +public: + + typedef T element_type; + + explicit shared_ptr(T * p = 0): px(p) + { + try // prevent leak if new throws + { + pn = new count_type(1); + } + catch(...) + { + checked_delete(p); + throw; + } + } + + ~shared_ptr() + { + if(--*pn == 0) + { + checked_delete(px); + delete pn; + } + } + + shared_ptr(shared_ptr const & r): px(r.px) // never throws + { + pn = r.pn; + ++*pn; + } + + shared_ptr & operator=(shared_ptr const & r) + { + shared_ptr(r).swap(*this); + return *this; + } + +#ifndef BOOST_NO_AUTO_PTR + + explicit shared_ptr(std::auto_ptr & r) + { + pn = new count_type(1); // may throw + px = r.release(); // fix: moved here to stop leak if new throws + } + + shared_ptr & operator=(std::auto_ptr & r) + { + shared_ptr(r).swap(*this); + return *this; + } + +#endif + + void reset(T * p = 0) + { + BOOST_ASSERT(p == 0 || p != px); + shared_ptr(p).swap(*this); + } + + T & operator*() const // never throws + { + BOOST_ASSERT(px != 0); + return *px; + } + + T * operator->() const // never throws + { + BOOST_ASSERT(px != 0); + return px; + } + + T * get() const // never throws + { + return px; + } + + long use_count() const // never throws + { + return *pn; + } + + bool unique() const // never throws + { + return *pn == 1; + } + + void swap(shared_ptr & other) // never throws + { + std::swap(px, other.px); + std::swap(pn, other.pn); + } + +private: + + T * px; // contained pointer + count_type * pn; // ptr to reference counter +}; + +template inline bool operator==(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() == b.get(); +} + +template inline bool operator!=(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() != b.get(); +} + +template inline bool operator<(shared_ptr const & a, shared_ptr const & b) +{ + return std::less()(a.get(), b.get()); +} + +template void swap(shared_ptr & a, shared_ptr & b) +{ + a.swap(b); +} + +// get_pointer() enables boost::mem_fn to recognize shared_ptr + +template inline T * get_pointer(shared_ptr const & p) +{ + return p.get(); +} + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_SHARED_PTR_NMT_HPP_INCLUDED diff --git a/include/boost/detail/winapi.hpp b/include/boost/detail/winapi.hpp new file mode 100644 index 0000000..0e9bb72 --- /dev/null +++ b/include/boost/detail/winapi.hpp @@ -0,0 +1,75 @@ +#ifndef BOOST_DETAIL_WINAPI_HPP_INCLUDED +#define BOOST_DETAIL_WINAPI_HPP_INCLUDED + +#if _MSC_VER >= 1020 +#pragma once +#endif + +// +// boost/detail/winapi.hpp - a lightweight version of +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +namespace boost +{ + +namespace detail +{ + +namespace winapi +{ + +typedef long long_type; +typedef unsigned long dword_type; +typedef void * handle_type; + +#if defined(_WIN64) + +typedef __int64 int_ptr_type; +typedef unsigned __int64 uint_ptr_type; +typedef __int64 long_ptr_type; +typedef unsigned __int64 ulong_ptr_type; + +#else + +typedef int int_ptr_type; +typedef unsigned int uint_ptr_type; +typedef long long_ptr_type; +typedef unsigned long ulong_ptr_type; + +#endif + +struct critical_section +{ + struct critical_section_debug * DebugInfo; + long_type LockCount; + long_type RecursionCount; + handle_type OwningThread; + handle_type LockSemaphore; + ulong_ptr_type SpinCount; +}; + +extern "C" __declspec(dllimport) long_type __stdcall InterlockedIncrement(long_type volatile *); +extern "C" __declspec(dllimport) long_type __stdcall InterlockedDecrement(long_type volatile *); +extern "C" __declspec(dllimport) long_type __stdcall InterlockedExchange(long_type volatile *, long_type); + +extern "C" __declspec(dllimport) void __stdcall Sleep(dword_type); + +extern "C" __declspec(dllimport) void __stdcall InitializeCriticalSection(critical_section *); +extern "C" __declspec(dllimport) void __stdcall EnterCriticalSection(critical_section *); +extern "C" __declspec(dllimport) void __stdcall LeaveCriticalSection(critical_section *); +extern "C" __declspec(dllimport) void __stdcall DeleteCriticalSection(critical_section *); + +} // namespace winapi + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_WINAPI_HPP_INCLUDED diff --git a/include/boost/intrusive_ptr.hpp b/include/boost/intrusive_ptr.hpp new file mode 100644 index 0000000..780fe78 --- /dev/null +++ b/include/boost/intrusive_ptr.hpp @@ -0,0 +1,202 @@ +#ifndef BOOST_INTRUSIVE_PTR_HPP_INCLUDED +#define BOOST_INTRUSIVE_PTR_HPP_INCLUDED + +// +// intrusive_ptr.hpp +// +// Copyright (c) 2001, 2002 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/intrusive_ptr.html for documentation. +// + +#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash +# pragma warning(push) +# pragma warning(disable:4284) // odd return type for operator-> +#endif + +#include // std::less + +namespace boost +{ + +// +// intrusive_ptr +// +// A smart pointer that uses intrusive reference counting. +// +// Relies on unqualified calls to +// +// void intrusive_ptr_add_ref(T * p); +// void intrusive_ptr_release(T * p); +// +// (p != 0) +// +// The object is responsible for destroying itself. +// + +template class intrusive_ptr +{ +private: + + typedef intrusive_ptr this_type; + +public: + + intrusive_ptr(): p_(0) + { + } + + intrusive_ptr(T * p): p_(p) + { + if(p_ != 0) intrusive_ptr_add_ref(p_); + } + + ~intrusive_ptr() + { + if(p_ != 0) intrusive_ptr_release(p_); + } + +#ifdef BOOST_MSVC6_MEMBER_TEMPLATES + + template intrusive_ptr(intrusive_ptr const & rhs): p_(rhs.get()) + { + if(p_ != 0) intrusive_ptr_add_ref(p_); + } + +#endif + + intrusive_ptr(intrusive_ptr const & rhs): p_(rhs.p_) + { + if(p_ != 0) intrusive_ptr_add_ref(p_); + } + +#ifdef BOOST_MSVC6_MEMBER_TEMPLATES + + template intrusive_ptr & operator=(intrusive_ptr const & rhs) + { + this_type(rhs).swap(*this); + return *this; + } + +#endif + + intrusive_ptr & operator=(intrusive_ptr const & rhs) + { + this_type(rhs).swap(*this); + return *this; + } + + intrusive_ptr & operator=(T * rhs) + { + this_type(rhs).swap(*this); + return *this; + } + + void swap(intrusive_ptr & rhs) + { + T * tmp = p_; + p_ = rhs.p_; + rhs.p_ = tmp; + } + + T * get() const + { + return p_; + } + + T & operator*() const + { + return *p_; + } + + T * operator->() const + { + return p_; + } + + bool empty() const + { + return p_ == 0; + } + + typedef bool (intrusive_ptr::*bool_type) () const; + + operator bool_type () const + { + return p_ == 0? 0: &intrusive_ptr::empty; + } + +private: + + T * p_; +}; + +template void swap(intrusive_ptr & lhs, intrusive_ptr & rhs) +{ + lhs.swap(rhs); +} + +template intrusive_ptr shared_dynamic_cast(intrusive_ptr const & p) +{ + return dynamic_cast(p.get()); +} + +template intrusive_ptr shared_static_cast(intrusive_ptr const & p) +{ + return static_cast(p.get()); +} + +template inline bool operator==(intrusive_ptr const & a, intrusive_ptr const & b) +{ + return a.get() == b.get(); +} + +template inline bool operator!=(intrusive_ptr const & a, intrusive_ptr const & b) +{ + return a.get() != b.get(); +} + +template inline bool operator<(intrusive_ptr const & a, intrusive_ptr const & b) +{ + return std::less(a.get(), b.get()); +} + +template inline bool operator==(intrusive_ptr const & a, T * b) +{ + return a.get() == b; +} + +template inline bool operator!=(intrusive_ptr const & a, T * b) +{ + return a.get() != b; +} + +template inline bool operator==(T * a, intrusive_ptr const & b) +{ + return a == b.get(); +} + +template inline bool operator!=(T * a, intrusive_ptr const & b) +{ + return a != b.get(); +} + +// mem_fn support + +template T * get_pointer(intrusive_ptr const & p) +{ + return p.get(); +} + +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif // #ifndef BOOST_INTRUSIVE_PTR_HPP_INCLUDED diff --git a/include/boost/scoped_array.hpp b/include/boost/scoped_array.hpp new file mode 100644 index 0000000..070925c --- /dev/null +++ b/include/boost/scoped_array.hpp @@ -0,0 +1,86 @@ +#ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED +#define BOOST_SCOPED_ARRAY_HPP_INCLUDED + +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/scoped_array.htm for documentation. +// + +#include +#include +#include // in case ptrdiff_t not in std +#include // for std::ptrdiff_t + +namespace boost +{ + +// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to +// is guaranteed, either on destruction of the scoped_array or via an explicit +// reset(). Use shared_array or std::vector if your needs are more complex. + +template class scoped_array // noncopyable +{ +private: + + T * ptr; + + scoped_array(scoped_array const &); + scoped_array & operator=(scoped_array const &); + +public: + + typedef T element_type; + + explicit scoped_array(T * p = 0) : ptr(p) // never throws + { + } + + ~scoped_array() // never throws + { + checked_array_delete(ptr); + } + + void reset(T * p = 0) // never throws + { + if (ptr != p) + { + checked_array_delete(ptr); + ptr = p; + } + } + + T & operator[](std::ptrdiff_t i) const // never throws + { + BOOST_ASSERT(ptr != 0); + BOOST_ASSERT(i >= 0); + return ptr[i]; + } + + T * get() const // never throws + { + return ptr; + } + + void swap(scoped_array & b) // never throws + { + T * tmp = b.ptr; + b.ptr = ptr; + ptr = tmp; + } + +}; + +template inline void swap(scoped_array & a, scoped_array & b) // never throws +{ + a.swap(b); +} + +} // namespace boost + +#endif // #ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED diff --git a/include/boost/scoped_ptr.hpp b/include/boost/scoped_ptr.hpp new file mode 100644 index 0000000..f452f7a --- /dev/null +++ b/include/boost/scoped_ptr.hpp @@ -0,0 +1,89 @@ +#ifndef BOOST_SCOPED_PTR_HPP_INCLUDED +#define BOOST_SCOPED_PTR_HPP_INCLUDED + +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation. +// + +#include +#include + +namespace boost +{ + +// scoped_ptr mimics a built-in pointer except that it guarantees deletion +// of the object pointed to, either on destruction of the scoped_ptr or via +// an explicit reset(). scoped_ptr is a simple solution for simple needs; +// use shared_ptr or std::auto_ptr if your needs are more complex. + +template class scoped_ptr // noncopyable +{ +private: + + T* ptr; + + scoped_ptr(scoped_ptr const &); + scoped_ptr & operator=(scoped_ptr const &); + +public: + + typedef T element_type; + + explicit scoped_ptr(T * p = 0): ptr(p) // never throws + { + } + + ~scoped_ptr() // never throws + { + checked_delete(ptr); + } + + void reset(T * p = 0) // never throws + { + if (ptr != p) + { + checked_delete(ptr); + ptr = p; + } + } + + T & operator*() const // never throws + { + BOOST_ASSERT(ptr != 0); + return *ptr; + } + + T * operator->() const // never throws + { + BOOST_ASSERT(ptr != 0); + return ptr; + } + + T * get() const // never throws + { + return ptr; + } + + void swap(scoped_ptr & b) // never throws + { + T * tmp = b.ptr; + b.ptr = ptr; + ptr = tmp; + } +}; + +template inline void swap(scoped_ptr & a, scoped_ptr & b) // never throws +{ + a.swap(b); +} + +} // namespace boost + +#endif // #ifndef BOOST_SCOPED_PTR_HPP_INCLUDED diff --git a/include/boost/shared_array.hpp b/include/boost/shared_array.hpp new file mode 100644 index 0000000..a820abc --- /dev/null +++ b/include/boost/shared_array.hpp @@ -0,0 +1,142 @@ +#ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED +#define BOOST_SHARED_ARRAY_HPP_INCLUDED + +// +// shared_array.hpp +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/shared_array.htm for documentation. +// + +#include // for broken compiler workarounds + +#ifndef BOOST_MSVC6_MEMBER_TEMPLATES +#include +#else + +#include +#include + +#include + +#include // for std::ptrdiff_t +#include // for std::swap +#include // for std::less + +namespace boost +{ + +// +// shared_array +// +// shared_array extends shared_ptr to arrays. +// The array pointed to is deleted when the last shared_array pointing to it +// is destroyed or reset. +// + +template class shared_array +{ +private: + + // Borland 5.5.1 specific workarounds + typedef checked_array_deleter deleter; + typedef shared_array this_type; + +public: + + typedef T element_type; + + explicit shared_array(T * p = 0): px(p), pn(p, deleter()) + { + } + + // + // Requirements: D's copy constructor must not throw + // + // shared_array will release p by calling d(p) + // + + template shared_array(T * p, D d): px(p), pn(p, d) + { + } + +// generated copy constructor, assignment, destructor are fine + + void reset(T * p = 0) + { + BOOST_ASSERT(p == 0 || p != px); + this_type(p).swap(*this); + } + + template void reset(T * p, D d) + { + this_type(p, d).swap(*this); + } + + T & operator[] (std::ptrdiff_t i) const // never throws + { + BOOST_ASSERT(px != 0); + BOOST_ASSERT(i >= 0); + return px[i]; + } + + T * get() const // never throws + { + return px; + } + + bool unique() const // never throws + { + return pn.unique(); + } + + long use_count() const // never throws + { + return pn.use_count(); + } + + void swap(shared_array & other) // never throws + { + std::swap(px, other.px); + pn.swap(other.pn); + } + +private: + + T * px; // contained pointer + detail::shared_count pn; // reference counter + +}; // shared_array + +template inline bool operator==(shared_array const & a, shared_array const & b) // never throws +{ + return a.get() == b.get(); +} + +template inline bool operator!=(shared_array const & a, shared_array const & b) // never throws +{ + return a.get() != b.get(); +} + +template inline bool operator<(shared_array const & a, shared_array const & b) // never throws +{ + return std::less()(a.get(), b.get()); +} + +template void swap(shared_array & a, shared_array & b) // never throws +{ + a.swap(b); +} + +} // namespace boost + +#endif // #ifndef BOOST_MSVC6_MEMBER_TEMPLATES + +#endif // #ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp new file mode 100644 index 0000000..39df95f --- /dev/null +++ b/include/boost/shared_ptr.hpp @@ -0,0 +1,324 @@ +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED +#define BOOST_SHARED_PTR_HPP_INCLUDED + +// +// shared_ptr.hpp +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. +// + +#include // for broken compiler workarounds + +#ifndef BOOST_MSVC6_MEMBER_TEMPLATES +#include +#else + +#include +#include + +#include + +#include // for std::auto_ptr +#include // for std::swap +#include // for std::less +#include // for std::bad_cast + +#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash +# pragma warning(push) +# pragma warning(disable:4284) // odd return type for operator-> +#endif + +namespace boost +{ + +namespace detail +{ + +struct static_cast_tag {}; +struct dynamic_cast_tag {}; +struct polymorphic_cast_tag {}; + +template struct shared_ptr_traits +{ + typedef T & reference; +}; + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +} // namespace detail + + +// +// shared_ptr +// +// An enhanced relative of scoped_ptr with reference counted copy semantics. +// The object pointed to is deleted when the last shared_ptr pointing to it +// is destroyed or reset. +// + +template class weak_ptr; +template class intrusive_ptr; + +template class shared_ptr +{ +private: + + // Borland 5.5.1 specific workarounds +// typedef checked_deleter deleter; + typedef shared_ptr this_type; + +public: + + typedef T element_type; + + shared_ptr(): px(0), pn() + { + } + + template + explicit shared_ptr(Y * p): px(p), pn(p, checked_deleter(), p) // Y must be complete + { + } + + // + // Requirements: D's copy constructor must not throw + // + // shared_ptr will release p by calling d(p) + // + + template shared_ptr(Y * p, D d): px(p), pn(p, d) + { + } + +// generated copy constructor, assignment, destructor are fine + + template + explicit shared_ptr(weak_ptr const & r): px(r.px), pn(r.pn) // may throw + { + } + + template + shared_ptr(shared_ptr const & r): px(r.px), pn(r.pn) // never throws + { + } + + template + shared_ptr(intrusive_ptr const & r): px(r.get()), pn(r.get()) // never throws + { + } + + template + shared_ptr(shared_ptr const & r, detail::static_cast_tag): px(static_cast(r.px)), pn(r.pn) + { + } + + template + shared_ptr(shared_ptr const & r, detail::dynamic_cast_tag): px(dynamic_cast(r.px)), pn(r.pn) + { + if (px == 0) // need to allocate new counter -- the cast failed + { + pn = detail::shared_count(); + } + } + + template + shared_ptr(shared_ptr const & r, detail::polymorphic_cast_tag): px(dynamic_cast(r.px)), pn(r.pn) + { + if (px == 0) + { + throw std::bad_cast(); + } + } + +#ifndef BOOST_NO_AUTO_PTR + + template + explicit shared_ptr(std::auto_ptr & r): px(r.get()), pn(r) + { + } + +#endif + +#if !defined(BOOST_MSVC) || (BOOST_MSVC > 1200) + + template + shared_ptr & operator=(shared_ptr const & r) // never throws + { + px = r.px; + pn = r.pn; // shared_count::op= doesn't throw + return *this; + } + +#endif + +#ifndef BOOST_NO_AUTO_PTR + + template + shared_ptr & operator=(std::auto_ptr & r) + { + this_type(r).swap(*this); + return *this; + } + +#endif + + void reset() + { + this_type().swap(*this); + } + + template void reset(Y * p) // Y must be complete + { + BOOST_ASSERT(p == 0 || p != px); // catch self-reset errors + this_type(p).swap(*this); + } + + template void reset(Y * p, D d) + { + this_type(p, d).swap(*this); + } + + typename detail::shared_ptr_traits::reference operator* () const // never throws + { + BOOST_ASSERT(px != 0); + return *px; + } + + T * operator-> () const // never throws + { + BOOST_ASSERT(px != 0); + return px; + } + + T * get() const // never throws + { + return px; + } + + bool unique() const // never throws + { + return pn.unique(); + } + + long use_count() const // never throws + { + return pn.use_count(); + } + + // implicit conversion to "bool" + + typedef long (this_type::*bool_type)() const; + + operator bool_type() const // never throws + { + return px == 0? 0: &this_type::use_count; + } + + bool operator! () const // never throws + { + return px == 0; + } + + void swap(shared_ptr & other) // never throws + { + std::swap(px, other.px); + pn.swap(other.pn); + } + +// Tasteless as this may seem, making all members public allows member templates +// to work in the absence of member template friends. (Matthew Langston) + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + +private: + + template friend class shared_ptr; + template friend class weak_ptr; + + +#endif + + T * px; // contained pointer + detail::shared_count pn; // reference counter + +}; // shared_ptr + +template inline bool operator==(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() == b.get(); +} + +template inline bool operator!=(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() != b.get(); +} + +#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 + +// Resolve the ambiguity between our op!= and the one in rel_ops + +template inline bool operator!=(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() != b.get(); +} + +#endif + +template inline bool operator<(shared_ptr const & a, shared_ptr const & b) +{ + return std::less()(a.get(), b.get()); +} + +template inline void swap(shared_ptr & a, shared_ptr & b) +{ + a.swap(b); +} + +template shared_ptr shared_static_cast(shared_ptr const & r) +{ + return shared_ptr(r, detail::static_cast_tag()); +} + +template shared_ptr shared_dynamic_cast(shared_ptr const & r) +{ + return shared_ptr(r, detail::dynamic_cast_tag()); +} + +template shared_ptr shared_polymorphic_cast(shared_ptr const & r) +{ + return shared_ptr(r, detail::polymorphic_cast_tag()); +} + +template shared_ptr shared_polymorphic_downcast(shared_ptr const & r) +{ + BOOST_ASSERT(dynamic_cast(r.get()) == r.get()); + return shared_static_cast(r); +} + +// get_pointer() enables boost::mem_fn to recognize shared_ptr + +template inline T * get_pointer(shared_ptr const & p) +{ + return p.get(); +} + +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif // #ifndef BOOST_MSVC6_MEMBER_TEMPLATES + +#endif // #ifndef BOOST_SHARED_PTR_HPP_INCLUDED diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp new file mode 100644 index 0000000..da28e87 --- /dev/null +++ b/include/boost/smart_ptr.hpp @@ -0,0 +1,9 @@ +// Boost smart_ptr.hpp header file -----------------------------------------// + +// For compatibility, this header includes the header for the four "classic" +// smart pointer class templates. + +#include +#include +#include +#include diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp new file mode 100644 index 0000000..e04b4f1 --- /dev/null +++ b/include/boost/weak_ptr.hpp @@ -0,0 +1,177 @@ +#ifndef BOOST_WEAK_PTR_HPP_INCLUDED +#define BOOST_WEAK_PTR_HPP_INCLUDED + +// +// weak_ptr.hpp +// +// Copyright (c) 2001, 2002 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/weak_ptr.htm for documentation. +// + +#include + +#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash +# pragma warning(push) +# pragma warning(disable:4284) // odd return type for operator-> +#endif + +namespace boost +{ + +template class weak_ptr +{ +private: + + // Borland 5.5.1 specific workarounds + typedef weak_ptr this_type; + +public: + + typedef T element_type; + + weak_ptr(): px(0), pn() + { + } + +// generated copy constructor, assignment, destructor are fine + + template + weak_ptr(weak_ptr const & r): px(r.px), pn(r.pn) // never throws + { + } + + template + weak_ptr(shared_ptr const & r): px(r.px), pn(r.pn) // never throws + { + } + +#if !defined(BOOST_MSVC) || (BOOST_MSVC > 1200) + + template + weak_ptr & operator=(weak_ptr const & r) // never throws + { + px = r.px; + pn = r.pn; + return *this; + } + + template + weak_ptr & operator=(shared_ptr const & r) // never throws + { + px = r.px; + pn = r.pn; + return *this; + } + +#endif + + void reset() + { + this_type().swap(*this); + } + + T * get() const // never throws; unsafe in multithreaded programs! + { + return pn.use_count() == 0? 0: px; + } + + long use_count() const // never throws + { + return pn.use_count(); + } + + bool expired() const // never throws + { + return pn.use_count() == 0; + } + + void swap(this_type & other) // never throws + { + std::swap(px, other.px); + pn.swap(other.pn); + } + + bool less(this_type const & rhs) const // implementation detail, never throws + { + return pn < rhs.pn; + } + +// Tasteless as this may seem, making all members public allows member templates +// to work in the absence of member template friends. (Matthew Langston) + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + +private: + + template friend class weak_ptr; + template friend class shared_ptr; + +#endif + + T * px; // contained pointer + detail::weak_count pn; // reference counter + +}; // weak_ptr + +template inline bool operator==(weak_ptr const & a, weak_ptr const & b) +{ + return a.get() == b.get(); +} + +template inline bool operator!=(weak_ptr const & a, weak_ptr const & b) +{ + return a.get() != b.get(); +} + +#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 + +// Resolve the ambiguity between our op!= and the one in rel_ops + +template inline bool operator!=(weak_ptr const & a, weak_ptr const & b) +{ + return a.get() != b.get(); +} + +#endif + +template inline bool operator<(weak_ptr const & a, weak_ptr const & b) +{ + return a.less(b); +} + +template void swap(weak_ptr & a, weak_ptr & b) +{ + a.swap(b); +} + +template shared_ptr make_shared(weak_ptr const & r) // never throws +{ + // optimization: avoid throw overhead + if(r.use_count() == 0) + { + return shared_ptr(); + } + + try + { + return shared_ptr(r); + } + catch(use_count_is_zero const &) + { + return shared_ptr(); + } +} + +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif // #ifndef BOOST_WEAK_PTR_HPP_INCLUDED diff --git a/index.htm b/index.htm new file mode 100644 index 0000000..676c78c --- /dev/null +++ b/index.htm @@ -0,0 +1,47 @@ + + + + + + +Boost Smart Pointer Library + + + + + + + + + + + + + +
c++boost.gif (8819 bytes)HomeLibrariesPeopleFAQMore
+

Smart Pointer Library

+

The smart pointer library includes five smart pointer class templates. Smart +pointers ease the management of memory dynamically allocated with C++ new +expressions. In addition, scoped_ptr can ease the management of memory +dynamically allocated in other ways.

+ + +

Revised 1 February 2002.

+ + + + diff --git a/msvcspeed.gif b/msvcspeed.gif new file mode 100644 index 0000000..56295ee Binary files /dev/null and b/msvcspeed.gif differ diff --git a/scoped_array.htm b/scoped_array.htm new file mode 100644 index 0000000..4df98a9 --- /dev/null +++ b/scoped_array.htm @@ -0,0 +1,145 @@ + + + + + + +scoped_array + + + + +

c++boost.gif (8819 bytes)scoped_array class template

+ +

The scoped_array class template stores a pointer to a dynamically allocated +array. (Dynamically allocated arrays are allocated with the C++ new[] +expression.) The array pointed to is guaranteed to be deleted, +either on destruction of the scoped_array, or via an explicit reset.

+ +

The scoped_array 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 +noncopyable) +signal its intent to retain ownership solely within the current scope. +Because it is noncopyable, it is +safer than shared_array for pointers which should not be copied.

+ +

Because scoped_array 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.

+ +

It cannot be used in C++ standard library containers. +See shared_array +if scoped_array does not meet your needs.

+ +

It cannot correctly hold a pointer to a single object. +See scoped_ptr +for that usage.

+ +

A std::vector is an alternative to a scoped_array that is +a bit heavier duty but far more flexible. +A boost::array is an alternative that does not use dynamic allocation.

+ +

The class template is parameterized on T, the type of the object +pointed to. T must meet the smart pointer +common requirements.

+ +

Synopsis

+ +
namespace boost {
+
+  template<typename T> class scoped_array : noncopyable {
+
+    public:
+      typedef T element_type;
+
+      explicit scoped_array(T * p = 0); // never throws
+      ~scoped_array(); // never throws
+
+      void reset(T * p = 0); // never throws
+
+      T & operator[](std::size_t i) const; // never throws
+      T * get() const; // never throws
+     
+      void swap(scoped_array & b); // never throws
+  };
+
+  template<typename T> void swap(scoped_array<T> & a, scoped_array<T> & b); // never throws
+
+}
+ +

Members

+ +

+element_type

+
typedef T element_type;
+

Provides the type of the stored pointer.

+ +

constructors

+
explicit scoped_array(T * p = 0); // never throws
+

Constructs a scoped_array, storing a copy of p, which must +have been allocated via a C++ new[] expression or be 0. +T is not required be a complete type. +See the smart pointer +common requirements.

+ +

destructor

+
~scoped_array(); // never throws
+

Deletes the array pointed to by the stored pointer. +Note that delete[] 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 common requirements.

+ +

reset

+
void reset(T * p = 0); // never throws
+

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++ new[] 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 common requirements.

+ +

subscripting

+
T & operator[](std::size_t i) const; // never throws
+

Returns a reference to element i of the array pointed to by the +stored pointer. +Behavior is undefined and almost certainly undesirable if the stored pointer is 0, +or if i is less than 0 or is greater than or equal to the number of elements +in the array.

+ +

get

+
T * get() const; // never throws
+

Returns the stored pointer. +T need not be a complete type. +See the smart pointer +common requirements.

+ +

swap

+
void swap(scoped_array & b); // never throws
+

Exchanges the contents of the two smart pointers. +T need not be a complete type. +See the smart pointer +common requirements.

+ +

Free Functions

+ +

swap

+
template<typename T> void swap(scoped_array<T> & a, scoped_array<T> & b); // never throws
+

Equivalent to a.swap(b). Matches the interface of std::swap. +Provided as an aid to generic programming.

+ +
+ +

Revised 1 February 2002

+ +

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.

+ + + + diff --git a/scoped_ptr.htm b/scoped_ptr.htm new file mode 100644 index 0000000..ec0057d --- /dev/null +++ b/scoped_ptr.htm @@ -0,0 +1,217 @@ + + + + + + +scoped_ptr + + + + +

c++boost.gif (8819 bytes)scoped_ptr class template

+ +

The scoped_ptr class template stores a pointer to a dynamically allocated +object. (Dynamically allocated objects are allocated with the C++ new +expression.) The object pointed to is guaranteed to be deleted, +either on destruction of the scoped_ptr, or via an explicit reset. +See the example.

+ +

The scoped_ptr 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 +noncopyable) +signal its intent to retain ownership solely within the current scope. +Because it is noncopyable, it is +safer than shared_ptr or std::auto_ptr for pointers which should not be +copied.

+ +

Because scoped_ptr 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.

+ +

It cannot be used in C++ Standard Library containers. +See shared_ptr +or std::auto_ptr if scoped_ptr does not meet your needs.

+ +

It cannot correctly hold a pointer to a +dynamically allocated array. See scoped_array +for that usage.

+ +

The class template is parameterized on T, the type of the object +pointed to. T must meet the smart pointer +common requirements.

+ +

Synopsis

+ +
namespace boost {
+
+  template<typename T> class scoped_ptr : noncopyable {
+
+   public:
+     typedef T element_type;
+
+     explicit scoped_ptr(T * p = 0); // never throws
+     ~scoped_ptr(); // never throws
+
+     void reset(T * p = 0); // never throws
+
+     T & operator*() const; // never throws
+     T * operator->() const; // never throws
+     T * get() const; // never throws
+     
+     void swap(scoped_ptr & b); // never throws
+  };
+
+  template<typename T> void swap(scoped_ptr<T> & a, scoped_ptr<T> & b); // never throws
+
+}
+ +

Members

+ +

element_type

+
typedef T element_type;
+

Provides the type of the stored pointer.

+ +

constructors

+
explicit scoped_ptr(T * p = 0); // never throws
+

Constructs a scoped_ptr, storing a copy of p, which must +have been allocated via a C++ new expression or be 0. +T is not required be a complete type. +See the smart pointer +common requirements.

+ +

destructor

+
~scoped_ptr(); // never throws
+

Deletes the object pointed to by the stored pointer. +Note that delete 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 common requirements.

+ +

reset

+
void reset(T * p = 0); // never throws
+

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++ new 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 common requirements.

+ +

indirection

+
T & operator*() const; // never throws
+

Returns a reference to the object pointed to by the stored pointer. +Behavior is undefined if the stored pointer is 0.

+
T * operator->() const; // never throws
+

Returns the stored pointer. Behavior is undefined if the stored pointer is 0.

+ +

get

+
T * get() const; // never throws
+

Returns the stored pointer. +T need not be a complete type. +See the smart pointer +common requirements.

+ +

swap

+
void swap(scoped_ptr & b); // never throws
+

Exchanges the contents of the two smart pointers. +T need not be a complete type. +See the smart pointer +common requirements.

+ +

Free Functions

+ +

swap

+
template<typename T> void swap(scoped_ptr<T> & a, scoped_ptr<T> & b); // never throws
+

Equivalent to a.swap(b). Matches the interface of std::swap. +Provided as an aid to generic programming.

+ +

Example

+ +

Here's an example that uses scoped_ptr.

+ +
+
#include <boost/scoped_ptr.hpp>
+#include <iostream>
+
+struct Shoe { ~Shoe() { std::cout << "Buckle my shoe\n"; } };
+
+class MyClass {
+    boost::scoped_ptr<int> ptr;
+  public:
+    MyClass() : ptr(new int) { *ptr = 0; }
+    int add_one() { return ++*ptr; }
+};
+
+void main()
+{
+    boost::scoped_ptr<Shoe> x(new Shoe);
+    MyClass my_instance;
+    std::cout << my_instance.add_one() << '\n';
+    std::cout << my_instance.add_one() << '\n';
+}
+
+ +

The example program produces the beginning of a child's nursery rhyme:

+ +
+
1
+2
+Buckle my shoe
+
+ +

Rationale

+ +

The primary reason to use scoped_ptr rather than auto_ptr 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.

+ +

A secondary reason to use scoped_ptr is to prevent a later maintenance programmer +from adding a function that transfers ownership by returning the auto_ptr, +because the maintenance programmer saw auto_ptr, and assumed ownership could safely +be transferred.

+ +

Think of bool vs int. We all know that under the covers bool is usually +just an int. Indeed, some argued against including bool in the +C++ standard because of that. But by coding bool rather than int, you tell your readers +what your intent is. Same with scoped_ptr; by using it you are signaling intent.

+ +

It has been suggested that scoped_ptr<T> is equivalent to +std::auto_ptr<T> const. Ed Brey pointed out, however, that +reset will not work on a std::auto_ptr<T> const.

+ +

Handle/Body Idiom

+ +

One common usage of scoped_ptr is to implement a handle/body (also +called pimpl) idiom which avoids exposing the body (implementation) in the header +file.

+ +

The scoped_ptr_example_test.cpp +sample program includes a header file, scoped_ptr_example.hpp, +which uses a scoped_ptr<> to an incomplete type to hide the +implementation. The +instantiation of member functions which require a complete type occurs in +the scoped_ptr_example.cpp +implementation file.

+ +

Frequently Asked Questions

+ +

Q. Why doesn't scoped_ptr have a release() member?
+A. Because the point of scoped_ptr is to signal intent, not +to transfer ownership. Use std::auto_ptr if ownership transfer is +required.

+ +
+ +

Revised 1 February 2002

+ +

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.

+ + + + diff --git a/scoped_ptr_example.cpp b/scoped_ptr_example.cpp new file mode 100644 index 0000000..3e2e511 --- /dev/null +++ b/scoped_ptr_example.cpp @@ -0,0 +1,16 @@ +// Boost scoped_ptr_example implementation file -----------------------------// + +#include "scoped_ptr_example.hpp" +#include + +class example::implementation +{ + public: + ~implementation() { std::cout << "destroying implementation\n"; } +}; + +example::example() : _imp( new implementation ) {} + +void example::do_something() { std::cout << "did something\n"; } + +example::~example() {} diff --git a/scoped_ptr_example.hpp b/scoped_ptr_example.hpp new file mode 100644 index 0000000..d3009f7 --- /dev/null +++ b/scoped_ptr_example.hpp @@ -0,0 +1,22 @@ +// Boost scoped_ptr_example header file ------------------------------------// + +#include +#include + +// The point of this example is to prove that even though +// example::implementation is an incomplete type in translation units using +// this header, scoped_ptr< implementation > is still valid because the type +// is complete where it counts - in the inplementation translation unit where +// destruction is actually instantiated. + +class example : private boost::noncopyable +{ + public: + example(); + ~example(); + void do_something(); + private: + class implementation; + boost::scoped_ptr< implementation > _imp; // hide implementation details +}; + diff --git a/scoped_ptr_example_test.cpp b/scoped_ptr_example_test.cpp new file mode 100644 index 0000000..1b77af2 --- /dev/null +++ b/scoped_ptr_example_test.cpp @@ -0,0 +1,10 @@ +// Boost scoped_ptr_example_test main program -------------------------------// + +#include "scoped_ptr_example.hpp" + +int main() +{ + example my_example; + my_example.do_something(); + return 0; +} diff --git a/shared_array.htm b/shared_array.htm new file mode 100644 index 0000000..3319553 --- /dev/null +++ b/shared_array.htm @@ -0,0 +1,224 @@ + + + + + + +shared_array + + + + +

c++boost.gif (8819 bytes)shared_array class template

+ +

The shared_array class template stores a pointer to a dynamically allocated +array. (Dynamically allocated array are allocated with the C++ new[] +expression.) The object pointed to is guaranteed to be deleted when +the last shared_array pointing to it is destroyed or reset.

+ +

Every shared_array meets the CopyConstructible +and Assignable requirements of the C++ Standard Library, and so +can be used in standard library containers. Comparison operators +are supplied so that shared_array works with +the standard library's associative containers.

+ +

Normally, a shared_array cannot correctly hold a pointer to a +single dynamically allocated object. See shared_ptr +for that usage.

+ +

Because the implementation uses reference counting, shared_array will not work +correctly with cyclic data structures. For example, if main() holds a shared_array +to A, which directly or indirectly holds a shared_array back to A, +A's use count will be 2. Destruction of the original shared_array +will leave A dangling with a use count of 1.

+ +

A shared_ptr to a std::vector is an alternative to a shared_array that is +a bit heavier duty but far more flexible.

+ +

The class template is parameterized on T, the type of the object +pointed to. T must meet the smart pointer +common requirements.

+ +

Synopsis

+ +
namespace boost {
+
+  template<typename T> class shared_array {
+
+    public:
+      typedef T element_type;
+
+      explicit shared_array(T * p = 0);
+      template<typename D> shared_array(T * p, D d);
+      ~shared_array(); // never throws
+
+      shared_array(shared_array const & r); // never throws
+
+      shared_array & operator=(shared_array const & r); // never throws
+
+      void reset(T * p = 0);
+      template<typename D> void reset(T * p, D d);
+
+      T & operator[](std::ptrdiff_t i) const() const; // never throws
+      T * get() const; // never throws
+
+      bool unique() const; // never throws
+      long use_count() const; // never throws
+
+      void swap(shared_array<T> & 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
+  template<typename T>
+    bool operator<(shared_array<T> const & a, shared_array<T> const & b); // never throws
+
+  template<typename T> void swap(shared_array<T> & a, shared_array<T> & b); // never throws
+
+}
+ +

Members

+ +

element_type

+
typedef T element_type;
+

Provides the type of the stored pointer.

+ +

constructors

+ +
explicit shared_array(T * p = 0);
+

Constructs a shared_array, storing a copy of p, which +must be a pointer to an array that was allocated via a C++ new[] expression or be 0. +Afterwards, the use count is 1 (even if p == 0; see ~shared_array). +The only exception which may be thrown by this constructor is std::bad_alloc. +If an exception is thrown, delete[] p is called.

+ +
template<typename D> shared_array(T * p, D d);
+

Constructs a shared_array, storing a copy of p and of d. +Afterwards, the use count is 1. +D's copy constructor and destructor must not throw. +When the the time comes to delete the array pointed to by p, the object +d is used in the statement d(p). Invoking the object d with +parameter p in this way must not throw. +The only exception which may be thrown by this constructor is std::bad_alloc. +If an exception is thrown, d(p) is called.

+ +
shared_array(shared_array const & r); // never throws
+

Constructs a shared_array, as if by storing a copy of the +pointer stored in r. Afterwards, the use count +for all copies is 1 more than the initial use count.

+ +

destructor

+ +
~shared_array(); // never throws
+

Decrements the use count. Then, if the use count is 0, +deletes the array pointed to by the stored pointer. +Note that delete[] on a pointer with a value of 0 is harmless. +T 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 common requirements.

+ +

assignment

+ +
shared_array & operator=(shared_array const & r); // never throws
+

Constructs a new shared_array as described above, +then replaces this shared_array with the new one, destroying the replaced object.

+ +

reset

+ +
void reset(T * p = 0);
+

Constructs a new shared_array as described above, +then replaces this shared_array with the new one, destroying the replaced object. +The only exception which may be thrown is std::bad_alloc. If +an exception is thrown, delete[] p is called.

+ +
template<typename D> void reset(T * p, D d);
+

Constructs a new shared_array as described above, +then replaces this shared_array with the new one, destroying the replaced object. +D's copy constructor must not throw. +The only exception which may be thrown is std::bad_alloc. If +an exception is thrown, d(p) is called.

+ +

indexing

+
T & operator[](std::size_t i) const; // never throws
+

Returns a reference to element i of the array pointed to by the stored pointer. +Behavior is undefined and almost certainly undesirable if the stored pointer is 0, +or if i is less than 0 or is greater than or equal to the number of elements +in the array.

+ +

get

+
T * get() const; // never throws
+

Returns the stored pointer. +T need not be a complete type. +See the smart pointer +common requirements.

+ +

unique

+
bool unique() const; // never throws
+

Returns true if no other shared_array is sharing ownership of +the stored pointer, false otherwise. +T need not be a complete type. +See the smart pointer +common requirements.

+ +

use_count

+
long use_count() const; // never throws
+

Returns the number of shared_array objects sharing ownership of the +stored pointer. +T need not be a complete type. +See the smart pointer +common requirements.

+

Because use_count is not necessarily efficient to implement for +implementations of shared_array 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.

+ +

swap

+
void swap(shared_ptr & b); // never throws
+

Exchanges the contents of the two smart pointers. +T need not be a complete type. +See the smart pointer +common requirements.

+ +

Free Functions

+ +

comparison

+
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
+

Compares the stored pointers of the two smart pointers. +T need not be a complete type. +See the smart pointer +common requirements.

+

The operator< overload is provided to define an ordering so that shared_array +objects can be used in associative containers such as std::map. +The implementation uses std::less<T *> 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 std::less<> on pointers is well-defined (20.3.3 [lib.comparisons] +paragraph 8).

+ +

swap

+
template<typename T>
+  void swap(shared_array<T> & a, shared_array<T> & b) // never throws
+

Equivalent to a.swap(b). Matches the interface of std::swap. +Provided as an aid to generic programming.

+ +
+ +

Revised 8 February 2002

+ +

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.

+ + + + diff --git a/shared_ptr.htm b/shared_ptr.htm new file mode 100644 index 0000000..be047d7 --- /dev/null +++ b/shared_ptr.htm @@ -0,0 +1,456 @@ + + + + shared_ptr + + + +

c++boost.gif (8819 bytes)shared_ptr + class template

+

Introduction
+ Synopsis
+ Members
+ Free Functions
+ Example
+ Handle/Body Idiom
+ Frequently Asked Questions
+ Smart Pointer Timings

+

Introduction

+

The shared_ptr class template stores a pointer to a dynamically allocated + object. (Dynamically allocated objects are allocated with the C++ new expression.) + The object pointed to is guaranteed to be deleted when the last shared_ptr + pointing to it is destroyed or reset. See the example.

+

Every shared_ptr meets the CopyConstructible and Assignable + requirements of the C++ Standard Library, and so can be used in standard + library containers. Comparison operators are supplied so that shared_ptr + works with the standard library's associative containers.

+

Normally, a shared_ptr cannot correctly hold a pointer to a dynamically + allocated array. See shared_array for + that usage.

+

Because the implementation uses reference counting, shared_ptr will not + work correctly with cyclic data structures. For example, if main() holds + a shared_ptr to A, which directly or indirectly holds a shared_ptr + back to A, A's use count will be 2. Destruction of the original shared_ptr + will leave A dangling with a use count of 1. Use weak_ptr + to "break cycles."

+

The class template is parameterized on T, the type of the object pointed + to. shared_ptr and most of its member functions place no + requirements on T; it is allowed to be an incomplete type, or + void. Member functions that do place additional requirements (constructors, + reset) are explicitly documented below.

+

shared_ptr<T> can be implicitly converted to shared_ptr<U> + whenever T* can be implicitly converted to U*. + In particular, shared_ptr<T> is implicitly convertible + to shared_ptr<T const>, to shared_ptr<U> + where U is an accessible base of T, and to + shared_ptr<void>.

+

Synopsis

+
namespace boost {
+
+  class use_count_is_zero: public std::exception;
+
+  template<typename T> class weak_ptr;
+
+  template<typename T> class shared_ptr {
+
+    public:
+
+      typedef T element_type;
+
+      shared_ptr ();
+      template<typename Y> explicit shared_ptr (Y * p);
+      template<typename Y, typename D> shared_ptr(Y * p, D d);
+      ~shared_ptr(); // never throws
+
+      shared_ptr(shared_ptr const & r); // never throws
+      template<typename Y> shared_ptr(shared_ptr<Y> const & r); // never throws
+      explicit shared_ptr(weak_ptr const & r);
+      template<typename Y> shared_ptr(std::auto_ptr<Y> & r);
+
+      shared_ptr & operator=(shared_ptr const & r); // never throws  
+      template<typename Y> shared_ptr & operator=(shared_ptr<Y> const & r); // never throws
+      template<typename Y> shared_ptr & operator=(std::auto_ptr<Y> & r);
+
+      void reset ();
+      template<typename Y> void reset (Y * p);
+      template<typename Y> template<typename D> void reset(Y * p, D d);
+
+      T & operator*() const; // never throws
+      T * operator->() const; // never throws
+      T * get() const; // never throws
+
+      bool unique() const; // never throws
+      long use_count() const; // never throws
+
+      operator implementation-defined-type () const; // never throws
+
+      void swap(shared_ptr<T> & b); // never throws
+  };
+
+  template<typename T, typename U>
+    bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
+  template<typename T, typename U>
+    bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
+  template<typename T>
+    bool operator<(shared_ptr<T> const & a, shared_ptr<T> const & b); // never throws
+
+  template<typename T> void swap(shared_ptr<T> & a, shared_ptr<T> & b); // never throws
+
+  template<typename T, typename U>
+    shared_ptr<T> shared_static_cast(shared_ptr<U> const & r); // never throws
+  template<typename T, typename U>
+    shared_ptr<T> shared_dynamic_cast(shared_ptr<U> const & r);
+  template<typename T, typename U>
+    shared_ptr<T> shared_polymorphic_cast(shared_ptr<U> const & r);
+  template<typename T, typename U>
+    shared_ptr<T> shared_polymorphic_downcast(shared_ptr<U> const & r); // never throws
+
+}
+

Members

+

element_type

+
typedef T element_type;
+
+

Provides the type of the template parameter T.

+
+

constructors

+
shared_ptr();
+
+

Effects: Constructs a shared_ptr.

+

Postconditions: use count is 1; the stored + pointer is 0.

+

Throws: std::bad_alloc.

+

Exception safety: If an exception is thrown, the constructor has no + effect.

+
+
template<typename Y> explicit shared_ptr(Y * p);
+
+

Requirements: p must be convertible to T *. Y + must be a complete type. The expression delete p must be + well-formed, must not invoke undefined behavior, and must not throw exceptions. +

+

Effects: Constructs a shared_ptr, storing a copy of p.

+

Postconditions: use count is 1.

+

Throws: std::bad_alloc.

+

Exception safety: If an exception is thrown, delete p is + called.

+

Notes: p must be a pointer to an object that was + allocated via a C++ new expression or be 0. The postcondition that + use count is 1 holds even if p is 0; invoking delete + on a pointer that has a value of 0 is harmless.

+
+
template<typename Y, typename D> shared_ptr(Y * p, D d);
+
+

Requirements: p must be convertible to T *. The copy + constructor and destructor of D must not throw. The expression d(p) + must be well-formed, must not invoke undefined behavior, and must not throw + exceptions. +

+

Effects: Constructs a shared_ptr, storing a copy of p and d.

+

Postconditions: use count is 1.

+

Throws: std::bad_alloc.

+

Exception safety: If an exception is thrown, d(p) is called.

+

Notes: When the the time comes to delete the object pointed to by p, + d(p) is invoked.

+
+
shared_ptr(shared_ptr const & r); // never throws
+template<typename Y> shared_ptr(shared_ptr<Y> const & r); // never throws
+
+

Effects: Constructs a shared_ptr, as if by storing a copy of the + pointer stored in r.

+

Postconditions: use count for all copies is + increased by one.

+

Throws: nothing.

+
+
explicit shared_ptr(weak_ptr const & r);
+
+

Effects: Constructs a shared_ptr, as if by storing a copy of the + pointer stored in r.

+

Postconditions: use count for all copies is + increased by one.

+

Throws: use_count_is_zero when r.use_count() == 0.

+

Exception safety: If an exception is thrown, the constructor has no + effect.

+
+
template<typename Y> shared_ptr(std::auto_ptr<Y> & r);
+
+

Effects: Constructs a shared_ptr, as if by storing a copy of r.release().

+

Postconditions: use count for all copies is + increased by one.

+

Throws: std::bad_alloc.

+

Exception safety: If an exception is thrown, the constructor has no + effect.

+
+

destructor

+
~shared_ptr(); // never throws
+
+

Effects: If *this is the sole owner (use_count() == 1), + destroys the object pointed to by the stored pointer.

+

Postconditions: use count for all remaining + copies is decreased by one.

+

Throws: nothing.

+
+

assignment

+
shared_ptr & operator=(shared_ptr const & r); // never throws
+template<typename Y> shared_ptr & operator=(shared_ptr<Y> const & r); // never throws
+template<typename Y> shared_ptr & operator=(std::auto_ptr<Y> & r);
+
+

Effects: Equivalent to shared_ptr(r).swap(*this).

+

Notes: The implementation is free to meet the effects (and the implied + guarantees) via different means, without creating a temporary. In particular, + in the example:

+
+shared_ptr<int> p(new int);
+shared_ptr<void> q(p);
+p = p;
+q = p;
+
+

both assignments may be no-ops.

+
+

reset

+
void reset();
+
+

Effects: Equivalent to shared_ptr().swap(*this).

+
+
template<typename Y> void reset(Y * p);
+
+

Effects: Equivalent to shared_ptr(p).swap(*this).

+
+
template<typename Y, typename D> void reset(Y * p, D d);
+
+

Effects: Equivalent to shared_ptr(p, d).swap(*this).

+
+

indirection

+
T & operator*() const; // never throws
+
+

Requirements: The stored pointer must not be 0.

+

Returns: a reference to the object pointed to by the stored pointer.

+

Throws: nothing.

+
+
T * operator->() const; // never throws
+
+

Requirements: The stored pointer must not be 0.

+

Returns: the stored pointer.

+

Throws: nothing.

+
+

get

+
T * get() const; // never throws
+
+

Returns: the stored pointer.

+

Throws: nothing.

+
+

unique

+
bool unique() const; // never throws
+
+

Returns: use_count() == 1.

+

Throws: nothing.

+

Notes: unique() may be faster than use_count().

+
+

use_count

+
long use_count() const; // never throws
+
+

Returns: the number of shared_ptr objects sharing ownership of the + stored pointer.

+

Throws: nothing.

+

Notes: use_count() is not necessarily efficient. Use only + for debugging and testing purposes, not for production code.

+
+

conversions

+
operator implementation-defined-type () const; // never throws
+
+

Returns: an implementation defined value that, when used in boolean + contexts, is equivalent to get() != 0.

+

Throws: nothing.

+

Notes: This conversion operator allows shared_ptr objects to be + used in boolean contexts, like if (p && p->valid()) {}. + The actual target type is typically a pointer to a member function, avloiding + many of the implicit conversion pitfalls.

+
+

swap

+
void swap(shared_ptr & b); // never throws
+
+

Effects: Exchanges the contents of the two smart pointers.

+

Throws: nothing.

+
+

Free Functions

+

comparison

+
template<typename T, typename U>
+  bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
+
+

Returns: a.get() == b.get().

+

Throws: nothing.

+
+
template<typename T, typename U>
+  bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
+
+

Returns: a.get() != b.get().

+

Throws: nothing.

+
+
template<typename T>
+  bool operator<(shared_ptr<T> const & a, shared_ptr<T> const & b); // never throws
+
+

Returns: an implementation-defined value such that operator< is + a strict weak ordering as described in section 25.3 [lib.alg.sorting] + of the C++ standard.

+

Throws: nothing.

+

Notes: Allows shared_ptr objects to be used as keys in + associative containers.

+
+

swap

+
template<typename T>
+  void swap(shared_ptr<T> & a, shared_ptr<T> & b) // never throws
+
+

Effects: Equivalent to a.swap(b).

+

Throws: nothing.

+

Notes: Matches the interface of std::swap. Provided as an aid to + generic programming.

+
+

shared_static_cast

+
template<typename T, typename U>
+  shared_ptr<T> shared_static_cast(shared_ptr<U> const & r); // never throws
+
+

Requires: The expression static_cast<T*>(r.get()) + must be well-formed.

+

Returns: A shared_ptr<T> object that stores a copy + of static_cast<T*>(r.get()) and shares ownership with r.

+

Throws: nothing.

+

Notes: the seemingly equivalent expression

+

shared_ptr<T>(static_cast<T*>(r.get()))

+

will eventually result in undefined behavior, attempting to delete the same + object twice.

+
+

shared_dynamic_cast

+
template<typename T, typename U>
+  shared_ptr<T> shared_dynamic_cast(shared_ptr<U> const & r);
+
+

Requires: The expression dynamic_cast<T*>(r.get()) + must be well-formed and its behavior defined.

+

Returns:

+
    +
  • + When dynamic_cast<T*>(r.get()) returns a nonzero value, a + shared_ptr<T> object that stores a copy of it and shares + ownership with r; +
  • + Otherwise, a default-constructed shared_ptr<T> object.
+

Throws: std::bad_alloc.

+

Exception safety: If an exception is thrown, the function has no effect.

+

Notes: the seemingly equivalent expression

+

shared_ptr<T>(dynamic_cast<T*>(r.get()))

+

will eventually result in undefined behavior, attempting to delete the same + object twice.

+
+

shared_polymorphic_cast

+
template<typename T, typename U>
+  shared_ptr<T> shared_polymorphic_cast(shared_ptr<U> const & r);
+
+

Requires: The expression + polymorphic_cast<T*>(r.get()) must be well-formed and + its behavior defined.

+

Returns: A shared_ptr<T> object that stores a copy + of polymorphic_cast<T*>(r.get()) + and shares ownership with r.

+

Throws: std::bad_cast when the pointer cannot be + converted.

+

Exception safety: If an exception is thrown, the function has no effect.

+
+

shared_polymorphic_downcast

+
template<typename T, typename U>
+  shared_ptr<T> shared_polymorphic_downcast(shared_ptr<U> const & r); // never throws
+
+

Requires: The expression + polymorphic_downcast<T*>(r.get()) must be well-formed + and its behavior defined.

+

Returns: A shared_ptr<T> object that stores a copy + of polymorphic_downcast<T*>(r.get()) + and shares ownership with r.

+

Throws: nothing.

+
+

Example

+

See shared_ptr_example.cpp for a complete + example program. The program builds a std::vector and std::set of shared_ptr + objects.

+

Note that after the containers have been populated, some of the shared_ptr + objects will have a use count of 1 rather than a use count of 2, since the set + is a std::set rather than a std::multiset, and thus does not + contain duplicate entries. Furthermore, the use count may be even higher at + various times while push_back and insert container operations are + performed. More complicated yet, the container operations may throw exceptions + under a variety of circumstances. Getting the memory management and exception + handling in this example right without a smart pointer would be a nightmare.

+

Handle/Body Idiom

+

One common usage of shared_ptr is to implement a handle/body (also called + pimpl) idiom which avoids exposing the body (implementation) in the header + file.

+

The shared_ptr_example2_test.cpp sample + program includes a header file, shared_ptr_example2.hpp, + which uses a shared_ptr<> to an incomplete type to hide the + implementation. The instantiation of member functions which require a complete + type occurs in the shared_ptr_example2.cpp + implementation file. Note that there is no need for an explicit destructor. + Unlike ~scoped_ptr, ~shared_ptr does not require that T be a complete + type.

+

Frequently Asked Questions

+

Q. There are several variations of shared pointers, with different + tradeoffs; why does the smart pointer library supply only a single + implementation? It would be useful to be able to experiment with each type so + as to find the most suitable for the job at hand?
+ A. An important goal of shared_ptr is to provide a + standard shared-ownership pointer. Having a single pointer type is important + for stable library interfaces, since different shared pointers typically cannot + interoperate, i.e. a reference counted pointer (used by library A) cannot share + ownership with a linked pointer (used by library B.)

+

Q. Why doesn't shared_ptr have template parameters supplying + traits or policies to allow extensive user customization?
+ A. Parameterization discourages users. The shared_ptr template is + carefully crafted to meet common needs without extensive parameterization. Some + day a highly configurable smart pointer may be invented that is also very easy + to use and very hard to misuse. Until then, shared_ptr is the smart + pointer of choice for a wide range of applications. (Those interested in policy + based smart pointers should read + Modern C++ Design by Andrei Alexandrescu.)

+

Q. I am not convinced. Default parameters can be used where appropriate to + hide the complexity. Again, why not policies?
+ A. Template parameters affect the type. See the answer to the first + question above.

+

Q. Why doesn't shared_ptr use a linked list implementation?
+ A. A linked list implementation does not offer enough advantages to + offset the added cost of an extra pointer. See timings + page. In addition, it is expensive to make a linked list implementation thread + safe.

+

Q. Why doesn't shared_ptr (or any of the other Boost smart + pointers) supply an automatic conversion to T*?
+ A. Automatic conversion is believed to be too error prone.

+

Q. Why does shared_ptr supply use_count()?
+ A. As an aid to writing test cases and debugging displays. One of the + progenitors had use_count(), and it was useful in tracking down bugs in a + complex project that turned out to have cyclic-dependencies.

+

Q. Why doesn't shared_ptr specify complexity requirements?
+ A. Because complexity requirements limit implementors and complicate the + specification without apparent benefit to shared_ptr users. For example, + error-checking implementations might become non-conforming if they had to meet + stringent complexity requirements.

+

Q. Why doesn't shared_ptr provide a release() function?
+ A. shared_ptr cannot give away ownership unless it's unique() + because the other copy will still destroy the object.

+

Consider:

+
shared_ptr<int> a(new int);
+shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2
+
+int * p = a.release();
+
+// Who owns p now? b will still call delete on it in its destructor.
+
+

Q. Why doesn't shared_ptr provide (your pet feature here)?
+ A. Because (your pet feature here) would mandate a reference counted + implementation or a linked list implementation, or some other specific + implementation. This is not the intent.

+
+

Revised  + 04 May 2002

+

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.

+ + diff --git a/shared_ptr_assign_fail.cpp b/shared_ptr_assign_fail.cpp new file mode 100644 index 0000000..993769a --- /dev/null +++ b/shared_ptr_assign_fail.cpp @@ -0,0 +1,31 @@ +#if defined(_MSC_VER) && !defined(__ICL) +#pragma warning(disable: 4786) // identifier truncated in debug info +#pragma warning(disable: 4710) // function not inlined +#pragma warning(disable: 4711) // function selected for automatic inline expansion +#pragma warning(disable: 4514) // unreferenced inline removed +#endif + +// +// shared_ptr_assign_fail.cpp - a negative test for shared_ptr assignment +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#include + +bool boost_error(char const *, char const *, char const *, long) +{ + return true; +} + +int main() +{ + boost::shared_ptr p; + p = new int(42); // assignment must fail + return 0; +} diff --git a/shared_ptr_example.cpp b/shared_ptr_example.cpp new file mode 100644 index 0000000..4db8fc6 --- /dev/null +++ b/shared_ptr_example.cpp @@ -0,0 +1,96 @@ +// Boost shared_ptr_example.cpp --------------------------------------------// + +// (C) Copyright Beman Dawes 2001. Permission to copy, +// use, modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided "as is" +// without express or implied warranty, and with no claim as to its +// suitability for any purpose. + +// See http://www.boost.org for most recent version including documentation. + +// Revision History +// 21 May 01 Initial complete version (Beman Dawes) + +// The original code for this example appeared in the shared_ptr documentation. +// Ray Gallimore pointed out that foo_set was missing a Compare template +// argument, so would not work as intended. At that point the code was +// turned into an actual .cpp file so it could be compiled and tested. + +#include +#include +#include +#include +#include + +// The application will produce a series of +// objects of type Foo which later must be +// accessed both by occurrence (std::vector) +// and by ordering relationship (std::set). + +struct Foo +{ + Foo( int _x ) : x(_x) {} + ~Foo() { std::cout << "Destructing a Foo with x=" << x << "\n"; } + int x; + /* ... */ +}; + +typedef boost::shared_ptr FooPtr; + +struct FooPtrOps +{ + bool operator()( const FooPtr & a, const FooPtr & b ) + { return a->x > b->x; } + void operator()( const FooPtr & a ) + { std::cout << a->x << "\n"; } +}; + +int main() +{ + std::vector foo_vector; + std::set foo_set; // NOT multiset! + + FooPtr foo_ptr( new Foo( 2 ) ); + foo_vector.push_back( foo_ptr ); + foo_set.insert( foo_ptr ); + + foo_ptr.reset( new Foo( 1 ) ); + foo_vector.push_back( foo_ptr ); + foo_set.insert( foo_ptr ); + + foo_ptr.reset( new Foo( 3 ) ); + foo_vector.push_back( foo_ptr ); + foo_set.insert( foo_ptr ); + + foo_ptr.reset ( new Foo( 2 ) ); + foo_vector.push_back( foo_ptr ); + foo_set.insert( foo_ptr ); + + std::cout << "foo_vector:\n"; + std::for_each( foo_vector.begin(), foo_vector.end(), FooPtrOps() ); + + std::cout << "\nfoo_set:\n"; + std::for_each( foo_set.begin(), foo_set.end(), FooPtrOps() ); + std::cout << "\n"; + +// Expected output: +// +// foo_vector: +// 2 +// 1 +// 3 +// 2 +// +// foo_set: +// 3 +// 2 +// 1 +// +// Destructing a Foo with x=2 +// Destructing a Foo with x=1 +// Destructing a Foo with x=3 +// Destructing a Foo with x=2 + + return 0; +} + diff --git a/shared_ptr_example2.cpp b/shared_ptr_example2.cpp new file mode 100644 index 0000000..746dd48 --- /dev/null +++ b/shared_ptr_example2.cpp @@ -0,0 +1,19 @@ +// Boost shared_ptr_example2 implementation file -----------------------------// + +#include "shared_ptr_example2.hpp" +#include + +class example::implementation +{ + public: + ~implementation() { std::cout << "destroying implementation\n"; } +}; + +example::example() : _imp( new implementation ) {} +example::example( const example & s ) : _imp( s._imp ) {} + +example & example::operator=( const example & s ) + { _imp = s._imp; return *this; } + +void example::do_something() + { std::cout << "use_count() is " << _imp.use_count() << "\n"; } diff --git a/shared_ptr_example2.hpp b/shared_ptr_example2.hpp new file mode 100644 index 0000000..93b77e5 --- /dev/null +++ b/shared_ptr_example2.hpp @@ -0,0 +1,26 @@ +// Boost shared_ptr_example2 header file -----------------------------------// + +#include + +// This example demonstrates the handle/body idiom (also called pimpl and +// several other names). It separates the interface (in this header file) +// from the implementation (in shared_ptr_example2.cpp). + +// Note that even though example::implementation is an incomplete type in +// some translation units using this header, shared_ptr< implementation > +// is still valid because the type is complete where it counts - in the +// shared_ptr_example2.cpp translation unit where functions requiring a +// complete type are actually instantiated. + +class example +{ + public: + example(); + example( const example & ); + example & operator=( const example & ); + void do_something(); + private: + class implementation; + boost::shared_ptr< implementation > _imp; // hide implementation details +}; + diff --git a/shared_ptr_example2_test.cpp b/shared_ptr_example2_test.cpp new file mode 100644 index 0000000..3a2cf53 --- /dev/null +++ b/shared_ptr_example2_test.cpp @@ -0,0 +1,15 @@ +// Boost shared_ptr_example2_test main program ------------------------------// + +#include "shared_ptr_example2.hpp" + +int main() +{ + example a; + a.do_something(); + example b(a); + b.do_something(); + example c; + c = a; + c.do_something(); + return 0; +} diff --git a/shared_ptr_mt_test.cpp b/shared_ptr_mt_test.cpp new file mode 100644 index 0000000..185bd99 --- /dev/null +++ b/shared_ptr_mt_test.cpp @@ -0,0 +1,181 @@ +#if defined(_MSC_VER) && !defined(__ICL) && !defined(__COMO__) +#pragma warning(disable: 4786) // identifier truncated in debug info +#pragma warning(disable: 4710) // function not inlined +#pragma warning(disable: 4711) // function selected for automatic inline expansion +#pragma warning(disable: 4514) // unreferenced inline removed +#endif + +// +// shared_ptr_mt_test.cpp - tests shared_ptr with multiple threads +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#include +#include + +#define BOOST_INCLUDE_MAIN +#include + +#include +#include +#include + +#include +#include + +// 'portable' thread framework + +class abstract_thread +{ +public: + + virtual ~abstract_thread() {} + virtual void run() = 0; +}; + +#if !defined(BOOST_HAS_PTHREADS) && defined(BOOST_HAS_WINTHREADS) + +char const * title = "Using Windows threads"; + +#include +#include + +typedef HANDLE pthread_t; + +unsigned __stdcall common_thread_routine(void * pv) +{ + abstract_thread * pt = static_cast(pv); + pt->run(); + delete pt; + return 0; +} + +int pthread_create(pthread_t * thread, void const *, unsigned (__stdcall * start_routine) (void*), void* arg) +{ + HANDLE h = (HANDLE)_beginthreadex(0, 0, start_routine, arg, 0, 0); + + if(h != 0) + { + *thread = h; + return 0; + } + else + { + return 1; // return errno; + } +} + +int pthread_join(pthread_t thread, void ** /*value_ptr*/) +{ + ::WaitForSingleObject(thread, INFINITE); + ::CloseHandle(thread); + return 0; +} + +#else + +char const * title = "Using POSIX threads"; + +#include + +extern "C" void * common_thread_routine(void * pv) +{ + abstract_thread * pt = static_cast(pv); + pt->run(); + delete pt; + return 0; +} + +#endif + +// + +template class thread: public abstract_thread +{ +public: + + explicit thread(F f): f_(f) + { + } + + void run() + { + f_(); + } + +private: + + F f_; +}; + +template pthread_t createThread(F f) +{ + std::auto_ptr p(new thread(f)); + + pthread_t r; + + if(pthread_create(&r, 0, common_thread_routine, p.get()) == 0) + { + p.release(); + return r; + } + + throw std::runtime_error("createThread failed."); +} + +// + +int const n = 1024 * 1024; + +void test(boost::shared_ptr const & pi) +{ + std::vector< boost::shared_ptr > v; + + for(int i = 0; i < n; ++i) + { + v.push_back(pi); + } +} + +int const m = 16; // threads + +#if defined(BOOST_LWM_USE_CRITICAL_SECTION) + char const * implementation = "critical section"; +#elif defined(BOOST_LWM_USE_PTHREADS) + char const * implementation = "pthread_mutex"; +#else + char const * implementation = "spinlock"; +#endif + +int test_main( int, char ** ) +{ + std::printf("%s: %s, %d threads, %d iterations: ", title, implementation, m, n); + + boost::shared_ptr pi(new int(42)); + + std::clock_t t = std::clock(); + + pthread_t a[m]; + + for(int i = 0; i < m; ++i) + { + a[i] = createThread( boost::bind(test, pi) ); + } + + for(int i = 0; i < m; ++i) + { + pthread_join(a[i], 0); + } + + t = std::clock() - t; + + std::printf("\n\n%.3f seconds.\n", static_cast(t) / CLOCKS_PER_SEC); + + return 0; +} diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp new file mode 100644 index 0000000..f96dfc6 --- /dev/null +++ b/shared_ptr_test.cpp @@ -0,0 +1,343 @@ +#if defined(_MSC_VER) && !defined(__ICL) && !defined(__COMO__) +#pragma warning(disable: 4786) // identifier truncated in debug info +#pragma warning(disable: 4710) // function not inlined +#pragma warning(disable: 4711) // function selected for automatic inline expansion +#pragma warning(disable: 4514) // unreferenced inline removed +#endif + +// +// shared_ptr_test.cpp - a test for shared_ptr.hpp and weak_ptr.hpp +// +// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#define BOOST_INCLUDE_MAIN +#include + +#include +#include + +bool boost_error(char const *, char const *, char const *, long) +{ + return true; +} + +namespace +{ + int cnt = 0; +} + +struct X +{ + X() + { + ++cnt; + std::cout << "X(" << this << ")::X()\n"; + } + + ~X() // virtual destructor deliberately omitted + { + --cnt; + std::cout << "X(" << this << ")::~X()\n"; + } + + virtual int id() const + { + return 1; + } + +private: + + X(X const &); + X & operator= (X const &); +}; + +struct Y: public X +{ + Y() + { + ++cnt; + std::cout << "Y(" << this << ")::Y()\n"; + } + + ~Y() + { + --cnt; + std::cout << "Y(" << this << ")::~Y()\n"; + } + + virtual int id() const + { + return 2; + } + +private: + + Y(Y const &); + Y & operator= (Y const &); +}; + +int * get_object() +{ + ++cnt; + std::cout << "get_object()\n"; + return &cnt; +} + +void release_object(int * p) +{ + BOOST_TEST(p == &cnt); + --cnt; + std::cout << "release_object()\n"; +} + +class Z: public virtual boost::counted_base +{ +public: + + Z() + { + ++cnt; + std::cout << "Z(" << this << ")::Z()\n"; + } + + ~Z() + { + --cnt; + std::cout << "Z(" << this << ")::~Z()\n"; + } + +private: + + Z(Z const &); + Z & operator= (Z const &); +}; + +template void test_is_X(boost::shared_ptr const & p) +{ + BOOST_TEST(p->id() == 1); + BOOST_TEST((*p).id() == 1); +} + +template void test_is_X(boost::weak_ptr const & p) +{ + BOOST_TEST(p.get() != 0); + BOOST_TEST(p.get()->id() == 1); +} + +template void test_is_Y(boost::shared_ptr const & p) +{ + BOOST_TEST(p->id() == 2); + BOOST_TEST((*p).id() == 2); +} + +template void test_is_Y(boost::weak_ptr const & p) +{ + BOOST_TEST(p.get() != 0); + BOOST_TEST(p.get()->id() == 2); +} + +template void test_eq(T const & a, T const & b) +{ + BOOST_TEST(a == b); + BOOST_TEST(!(a != b)); + BOOST_TEST(!(a < b)); + BOOST_TEST(!(b < a)); +} + +template void test_ne(T const & a, T const & b) +{ + BOOST_TEST(!(a == b)); + BOOST_TEST(a != b); + BOOST_TEST(a < b || b < a); + BOOST_TEST(!(a < b && b < a)); +} + +template void test_eq2(T const & a, U const & b) +{ + BOOST_TEST(a == b); + BOOST_TEST(!(a != b)); +} + +template void test_ne2(T const & a, U const & b) +{ + BOOST_TEST(!(a == b)); + BOOST_TEST(a != b); +} + +template void test_is_zero(boost::shared_ptr const & p) +{ + BOOST_TEST(!p); + BOOST_TEST(p.get() == 0); +} + +template void test_is_nonzero(boost::shared_ptr const & p) +{ + BOOST_TEST(p); + BOOST_TEST(p.get() != 0); +} + +int test_main(int, char * []) +{ + using namespace boost; + + { + shared_ptr p(new Y); + shared_ptr p2(new X); + + test_is_nonzero(p); + test_is_nonzero(p2); + test_is_Y(p); + test_is_X(p2); + test_ne(p, p2); + + { + shared_ptr q(p); + test_eq(p, q); + } + + shared_ptr p3 = shared_dynamic_cast(p); + shared_ptr p4 = shared_dynamic_cast(p2); + + test_is_nonzero(p3); + test_is_zero(p4); + + BOOST_TEST(p.use_count() == 2); + BOOST_TEST(p2.use_count() == 1); + BOOST_TEST(p3.use_count() == 2); + BOOST_TEST(p4.use_count() == 1); + + test_is_Y(p3); + test_eq2(p, p3); + test_ne2(p2, p4); + + shared_ptr p5(p); + + test_is_nonzero(p5); + test_eq2(p, p5); + + std::cout << "--\n"; + + p.reset(); + p2.reset(); + p3.reset(); + p4.reset(); + + test_is_zero(p); + test_is_zero(p2); + test_is_zero(p3); + test_is_zero(p4); + + std::cout << "--\n"; + + BOOST_TEST(p5.use_count() == 1); + + weak_ptr wp1; + + BOOST_TEST(wp1.use_count() == 0); + BOOST_TEST(wp1.get() == 0); + + try + { + shared_ptr sp1(wp1); + BOOST_ERROR("shared_ptr sp1(wp1) failed to throw"); + } + catch(boost::use_count_is_zero const &) + { + } + + test_is_zero(boost::make_shared(wp1)); + + weak_ptr wp2 = shared_static_cast(p5); + + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(wp2.get() != 0); + test_is_Y(wp2); + test_ne(wp1, wp2); + + // Scoped to not affect the subsequent use_count() tests. + { + shared_ptr sp2(wp2); + test_is_nonzero(boost::make_shared(wp2)); + } + + weak_ptr wp3 = shared_dynamic_cast(boost::make_shared(wp2)); + + BOOST_TEST(wp3.use_count() == 1); + BOOST_TEST(wp3.get() != 0); + test_eq2(wp2, wp3); + + weak_ptr wp4(wp3); + + BOOST_TEST(wp4.use_count() == 1); + BOOST_TEST(wp4.get() != 0); + test_eq(wp2, wp4); + + wp1 = p2; + BOOST_TEST(wp1.get() == 0); + + // Note the following test. Construction succeeds, + // but make_shared() returns a null shared_ptr with + // use_count() == 2. + + shared_ptr sp1(wp1); + test_is_zero(boost::make_shared(wp1)); + + BOOST_TEST(p2.use_count() == 2); + BOOST_TEST(sp1.use_count() == 2); + BOOST_TEST(wp1.use_count() == 2); + + // + + wp1 = p4; + wp1 = wp3; + wp1 = wp2; + + BOOST_TEST(wp1.use_count() == 1); + BOOST_TEST(wp1.get() != 0); + test_eq(wp1, wp2); + + weak_ptr wp5; + + bool b1 = wp1 < wp5; + bool b2 = wp5 < wp1; + + p5.reset(); + + BOOST_TEST(wp1.use_count() == 0); + BOOST_TEST(wp1.get() == 0); + + BOOST_TEST(wp2.use_count() == 0); + BOOST_TEST(wp2.get() == 0); + + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(wp3.get() == 0); + + // Test operator< stability for std::set< weak_ptr<> > + // Thanks to Joe Gottman for pointing this out + + BOOST_TEST(b1 == (wp1 < wp5)); + BOOST_TEST(b2 == (wp5 < wp1)); + + { + // note that both get_object and release_object deal with int* + shared_ptr p6(get_object(), release_object); + } + + { + // test intrusive counting + boost::shared_ptr pv(new Z); + boost::shared_ptr pz = boost::shared_static_cast(pv); + BOOST_TEST(pz.use_count() == pz->use_count()); + } + } + + BOOST_TEST(cnt == 0); + + return 0; +} diff --git a/shared_ptr_timing_test.cpp b/shared_ptr_timing_test.cpp new file mode 100644 index 0000000..299261b --- /dev/null +++ b/shared_ptr_timing_test.cpp @@ -0,0 +1,41 @@ +#if defined(_MSC_VER) && !defined(__ICL) && !defined(__COMO__) +#pragma warning(disable: 4786) // identifier truncated in debug info +#pragma warning(disable: 4710) // function not inlined +#pragma warning(disable: 4711) // function selected for automatic inline expansion +#pragma warning(disable: 4514) // unreferenced inline removed +#endif + +// +// shared_ptr_timing_test.cpp - use to evaluate the impact of thread safety +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#include +#include +#include +#include + +int const n = 8 * 1024 * 1024; + +int main() +{ + std::vector< boost::shared_ptr > v; + boost::shared_ptr pi(new int); + + std::clock_t t = std::clock(); + + for(int i = 0; i < n; ++i) + { + v.push_back(pi); + } + + t = std::clock() - t; + + std::cout << static_cast(t) / CLOCKS_PER_SEC << '\n'; +} diff --git a/smart_ptr.htm b/smart_ptr.htm new file mode 100644 index 0000000..1e045f1 --- /dev/null +++ b/smart_ptr.htm @@ -0,0 +1,207 @@ + + + + + + +Smart Pointers + + + + +

c++boost.gif (8819 bytes)Smart +Pointers

+ +

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.

+ +

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.

+ +

The smart pointer library provides five smart pointer class templates:

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
scoped_ptr<boost/scoped_ptr.hpp>Simple sole ownership of single objects. Noncopyable.
scoped_array<boost/scoped_array.hpp>Simple sole ownership of arrays. Noncopyable.
shared_ptr<boost/shared_ptr.hpp>Object ownership shared among multiple pointers
shared_array<boost/shared_array.hpp>Array ownership shared among multiple pointers.
weak_ptr<boost/weak_ptr.hpp>Non-owning observers of an object owned by shared_ptr.
+
+ +

These templates are designed to complement the std::auto_ptr template.

+ +

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.

+ +

A test program, smart_ptr_test.cpp, is +provided to verify correct operation.

+ +

A page on compatibility with older versions of +the Boost smart pointer library describes some of the changes since earlier versions +of the smart pointer implementation.

+ +

A page on smart pointer timings will be of +interest to those curious about performance issues.

+ +

Common Requirements

+ +

These smart pointer class templates have a template parameter, T, 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 operator delete +for objects of type T throw exceptions.

+ +

T may be an incomplete type at the point of smart pointer +declaration. Unless otherwise specified, it is required that T +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 checked_delete +function template.

+ +

Rationale

+ +

The requirements on T 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 T 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.

+ +

Note that scoped_ptr requires that T be a complete type +at destruction time, but shared_ptr does not.

+ +

Exception Safety

+ +

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 T meets the +common requirements) is std::bad_alloc, +and that is thrown only by functions which are explicitly documented as possibly +throwing std::bad_alloc.

+ +

Exception-specifications

+ +

Exception-specifications are not used; see +exception-specification +rationale.

+ +

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: +// never throws.

+ +

Functions which destroy objects of the pointed to type are prohibited from +throwing exceptions by the common requirements.

+ +

History and Acknowledgements

+ +

January 2002. Peter Dimov reworked all four classes, adding features, fixing bugs, +and splitting them into four separate headers, and added weak_ptr. See the +compatibility page for a summary of the changes.

+ +

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.

+ +

November 1999. Darin Adler provided operator ==, operator !=, and std::swap +and std::less specializations for shared types.

+ +

September 1999. Luis Coelho provided shared_ptr::swap and shared_array::swap

+ +

May 1999. In April and May, 1999, Valentin Bonnard and David Abrahams +made a number of suggestions resulting in numerous improvements.

+ +

October 1998. In 1994 Greg Colvin proposed to the C++ Standards Committee +classes named auto_ptr and counted_ptr which +were very similar to what we now call scoped_ptr and shared_ptr. +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, counted_ptr was rejected +and surprising transfer-of-ownership semantics were added to auto_ptr.

+ +

Beman Dawes proposed reviving the original semantics under the names safe_ptr +and counted_ptr 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 std::auto_ptr interface, and various +function signatures and semantics were finalized.

+ +

Over the next three months, several implementations were considered for shared_ptr, +and discussed on the boost.org 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: + +

    +
  • Direct detached: the shared_ptr contains a pointer to the object, and a + pointer to the count.
  • +
  • Indirect detached: the shared_ptr contains a pointer to a helper object, + which in turn contains a pointer to the object and the count.
  • +
  • Embedded attached: the count is a member of the object pointed to.
  • +
  • Placement attached: the count is attached via operator new manipulations.
  • +
+ +

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.

+ +

But Greg Colvin and Jerry Schwarz argued that "parameterization will +discourage users", and in the end we choose to supply only the direct +implementation.

+ +
+ +

Revised 4 February 2002

+ +

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.

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

c++boost.gif (8819 bytes)Smart Pointer Timings

+ +

In late January 2000, Mark Borgerding put forward a suggestion to boost for + a new design of smart pointer whereby an intrusive doubly linked list is used + to join together all instances of smart pointers sharing a given raw pointer. + This allowed avoidance of the costly heap allocation of a reference count that + occurred in the initial construction of the then current version of boost::shared_ptr. + Of course, nothing is for free and the benefit here was gained at the expense + of increased size and more costly copy operations. A debate ensued on the boost + mailing list and the tests which this page describes were performed to provide + a guide for current and future investigations into smart pointer implementation + strategies.

+

Thanks are due to Dave Abrahams, +Gavin Collings, +Greg Colvin and +Beman Dawes + for test code and trial implementations, the final version of which can be found + in .zip format here.

+

Description

+

Two tests were run: the first aimed to obtain timings for two basic individual + operations:

+
    +
  1. Initial construction from raw pointer.
  2. +
  3. An amortized copy operation consisting of half an assignment and half a + copy construction - designed to reflect average usage.
  4. +
+

The second attempted to gain more insight into normal usage by timing the fill + and sort algorithms for vectors and lists filled with the various smart pointers.

+

Five smart pointer implementation strategies were tested:

+
    +
  1. Counted pointer using a heap allocated reference count, this is referred + to as simple counted.
  2. +
  3. Counted pointer using a special purpose allocator for the reference count + - special counted.
  4. +
  5. Counted pointer using an intrusive reference count - intrusive.
  6. +
  7. Linked pointer as described above - linked.
  8. +
  9. Cyclic pointer, a counted implementation using a std::deque for allocation + with provision for weak pointers and garbage collection of cycles of pointers + - cyclic.
  10. +
+

on two compilers:

+
    +
  1. MSVC 6.0 service pack 3, using default release optimization mode (/O2 - + optimized for speed, no inlining of functions defined outside a class body + unless specified as inline).
  2. +
  3. gcc 2.95.2 using full optimization (-O3 -DNDEBUG).
  4. +
+

Additionally, generated pointer sizes (taking into account struct alignment) + were compared, as were generated code sizes for MSVC mainly by manual inspection + of generated assembly code - a necessity due to function inlining.

+

All tests were run on a PII-200 running Windows NT version 4.0

+

 

+

Operation Timing Test Results

+

The following graphs show the overall time in nanoseconds to acquire a pointer + (default construction) perform n amortized copy operations on it and finally + release it. The initial allocation time for the contained pointer is not included, + although the time for it's deallocation is. The contained pointer pointed to + a trivial class, but for the inclusion of an intrusive reference count for the + benefit of the intrusive counted shared pointer. A dumb pointer (i.e. a smart + pointer that simply acquires and releases its contained pointer with no extra + overhead) and a raw pointer were also included for comparison.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
   
  MSVC speed graph 
   
 GCC speed graph 
   
+

 

+

Fitting straight lines to the above plots gives the following figures for initialization + and amortized copy operation for the two compilers (times in nanoseconds, errors + at two standard deviations) : -

+

 

+

MSVC

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
initialization
+
copy operation
+
simple counted
+
3000 +/- 170104 +/- 31
+
special counted
+
1330 +/- 5085 +/- 9
+
intrusive
+
1000 +/- 2071 +/- 3
linked970 +/- 60136 +/- 10
cyclic1290 +/- 70112 +/- 12
dumb1020 +/- 2010 +/- 4
+
raw
+
1038 +/- 3010 +/- 5
+

 

+

GCC

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
initialization
+
copy operation
+
simple counted
+
4620 +/- 150301 +/- 28
+
special counted
+
1990 +/- 40264 +/- 7
+
intrusive
+
1590 +/- 70181 +/- 12
linked1470 +/- 140345 +/- 26
cyclic2180 +/- 100330 +/- 18
dumb1590 +/- 7074 +/- 12
+
raw
+
1430 +/- 6027 +/- 11
+

Note that the above times include a certain amount of loop overhead etc. for + each operation. An estimate of the pure smart pointer operation time 'overhead' + can be obtained by subtracting the dumb or raw figure from the smart pointer + time of interest.

+

Detail

+

The test involved iterating a loop which creates raw pointers. These were then + shared among a varying number (set size) of smart pointers. A range of set sizes + was used and then a line fitted to get a linear relation with number of initializations + and copy-operations. A spreadsheet was used for the line fit, and to produce + the performance graphs above.

+

 

+

Container Test Results

+

To gain some insight in to operation within real life programs, this test was + devised. Smart pointers were used to fill standard containers which were then + sorted.

+

In this case, the contained pointer pointed to a class which initializes a + private data member to a random value in its default constructor. This value + is used subsequently for the sort comparison test. The class also contains an + intrusive reference count for the benefit of the intrusive counted pointer.

+

All times are in seconds for 300,000 contained pointers.

+

GCC

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 vectorlist
+
+
+
fill
+
sortfillsort
+
simple counted
+
46.542.4447.093.22
+
special counted
+
14.022.837.283.21
+
intrusive
+
12.151.917.993.08
linked12.462.328.143.27
cyclic22.603.191.633.18
+
raw
+
11.810.2427.510.77
+

 

+

MSVC

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 vectorlist
+
+
+
fill
+
sortfillsort
+
simple counted
+
1.832.371.864.85
+
special counted
+
1.042.351.384.58
+
intrusive
+
1.041.841.164.29
linked1.082.001.214.33
cyclic1.382.841.474.73
+
raw
+
0.670.281.241.81
+

 

+

Code Size

+

The following code sizes were determined by inspection of generated code for + MSVC only. Sizes are given in the form N / M / I where:

+
    +
  • N is the instruction count of the operation
  • +
  • M is the size of the code in bytes
  • +
  • I determines whether generated code was inlined or not I = inline, O = "outline"
  • +
+

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
ptr()
+
ptr(p)ptr(ptr)op=() +
~ptr()
+
+
simple counted
+
38/110/O38/110/O9/23/I22/57/I17/40/I
+
special counted
+
50/141/O50/141/O9/23/I23/64/I13/38/I
+
intrusive
+
1/2/I3/6/I3/6/I6/11/I6/11/I
+
linked
+
5/19/I5/15/I10/30/I27/59/I14/38/I
+

During the code inspection, a couple of minor points were noticed: -

+
    +
  • Function inlining was critical to performance.
  • +
  • For MSVC, at least, a "delete 0" caused execution of 11 assembly + instructions, including a function call. So in cases where performance is + at an absolute premium it can be worth inserting the extra manual test.
  • +
+

 

+

Data Size

+

The following smart pointer sizes were obtained in bytes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
MSVC
+
+
GCC
+
+
simple counted
+
+
8
+
+
8
+
+
special counted
+
+
8
+
+
12
+
+
intrusive
+
+
4
+
+
4
+
+
linked
+
+
12
+
+
12
+
+
cyclic
+
+
8
+
+
8
+
+

 

+

Summary

+

The timing results mainly speak for themselves: clearly an intrusive pointer + outperforms all others and a simple heap based counted pointer has poor performance + relative to other implementations. The selection of an optimal non-intrusive + smart pointer implementation is more application dependent, however. Where small + numbers of copies are expected, it is likely that the linked implementation + will be favoured. Conversely, for larger numbers of copies a counted pointer + with some type of special purpose allocator looks like a win. Other factors + to bear in mind are: -

+
    +
  • Deterministic individual, as opposed to amortized, operation time. This + weighs against any implementation depending on an allocator.
  • +
  • Multithreaded synchronization. This weighs against an implementation which + spreads its information as in the case of linked pointer.
  • +
+
+

Revised 19 August 2001 +

+

© Copyright Gavin Collings 2000. Permission to copy, use, modify, sell +and distribute this document is granted provided this copyright notice appears in all +copies. This document is provided "as is" without express or implied warranty, +and with no claim as to its suitability for any purpose.

+ + diff --git a/weak_ptr.htm b/weak_ptr.htm new file mode 100644 index 0000000..72104fb --- /dev/null +++ b/weak_ptr.htm @@ -0,0 +1,243 @@ + + + + weak_ptr + + + +

c++boost.gif (8819 bytes)weak_ptr + class template

+

The weak_ptr class template stores a pointer to an object that's already + managed by a shared_ptr. When the object last shared_ptr to the + object goes away and the object is deleted, all weak_ptr objects have + their stored pointers set to 0.

+

Every weak_ptr meets the CopyConstructible and Assignable requirements + of the C++ Standard Library, and so can be used in standard library containers. + Comparison operators are supplied so that weak_ptr works with the + standard library's associative containers.

+

The class template is parameterized on T, the type of the object pointed + to. T must meet the smart pointer + common requirements.

+

Compared to shared_ptr, weak_ptr 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:

+
+shared_ptr<int> p(new int(5));
+weak_ptr<int> q(p);
+
+// some time later
+
+if(int * r = q.get())
+{
+	// use *r
+}
+
+

Imagine that after the if, but immediately before r + is used, another thread executes the statement p.reset(). Now r + is a dangling pointer.

+

The solution to this problem is to create a temporary shared_ptr + from q:

+
+shared_ptr<int> p(new int(5));
+weak_ptr<int> q(p);
+
+// some time later
+
+if(shared_ptr<int> r = make_shared(q))
+{
+	// use *r
+}
+
+

Now r holds a reference to the object that was pointed by q. + Even if p.reset() is executed in another thread, the object will + stay alive until r goes out of scope (or is reset.)

+

Synopsis

+
namespace boost {
+
+  template<typename T> class weak_ptr {
+
+    public:
+      typedef T element_type;
+
+      weak_ptr();
+      template<typename Y> weak_ptr(shared_ptr<Y> const & r); // never throws
+      ~weak_ptr(); // never throws
+
+      weak_ptr(weak_ptr const & r); // never throws
+      template<typename Y> weak_ptr(weak_ptr<Y> const & r); // never throws
+
+      weak_ptr & operator=(weak_ptr const & r); // never throws  
+      template<typename Y> weak_ptr & operator=(weak_ptr<Y> const & r); // never throws
+      template<typename Y> weak_ptr & operator=(shared_ptr<Y> const & r); // never throws
+
+      void reset();
+      T * get() const; // never throws; unsafe in multithreaded code!
+
+      long use_count() const; // never throws
+      bool expired() const; // never throws
+
+      void swap(weak_ptr<T> & b); // never throws
+  };
+
+  template<typename T, typename U>
+    bool operator==(weak_ptr<T> const & a, weak_ptr<U> const & b); // never throws
+  template<typename T, typename U>
+    bool operator!=(weak_ptr<T> const & a, weak_ptr<U> const & b); // never throws
+  template<typename T>
+    bool operator<(weak_ptr<T> const & a, weak_ptr<T> const & b); // never throws
+
+  template<typename T> void swap(weak_ptr<T> & a, weak_ptr<T> & b); // never throws
+
+  template<typename T>
+    shared_ptr<T> make_shared(weak_ptr<T> const & r); // never throws
+
+}
+
+

Members

+

element_type

+
typedef T element_type;
+
+

Provides the type of the template parameter T.

+
+

constructors

+
explicit weak_ptr();
+
+

Effects: Constructs a weak_ptr.

+

Postconditions: use count is 0; the stored + pointer is 0.

+

Throws: std::bad_alloc.

+

Exception safety: If an exception is thrown, the constructor has no + effect.

+

Notes: T need not be a complete type. See the smart pointer + common requirements.

+
+
template<typename Y> weak_ptr(shared_ptr<Y> const & r); // never throws
+
+

Effects: Constructs a weak_ptr, as if by storing a copy of the + pointer stored in r.

+

Throws: nothing.

+

Notes: The use count for all copies is + unchanged. When the last shared_ptr is destroyed, the use count and + stored pointer become 0.

+
+
weak_ptr(weak_ptr const & r); // never throws
+template<typename Y> weak_ptr(weak_ptr<Y> const & r); // never throws
+
+

Effects: Constructs a weak_ptr, as if by storing a copy of the + pointer stored in r.

+

Throws: nothing.

+

Notes: The use count for all copies is + unchanged.

+
+

destructor

+
~weak_ptr(); // never throws
+
+

Effects: Destroys this weak_ptr but has no effect on the object + its stored pointer points to.

+

Throws: nothing.

+

Notes: T need not be a complete type. See the smart pointer + common requirements.

+
+

assignment

+
weak_ptr & operator=(weak_ptr const & r); // never throws
+template<typename Y> weak_ptr & operator=(weak_ptr<Y> const & r); // never throws
+template<typename Y> weak_ptr & operator=(shared_ptr<Y> const & r); // never throws
+
+

Effects: Equivalent to weak_ptr(r).swap(*this).

+

Throws: nothing.

+

Notes: The implementation is free to meet the effects (and the implied + guarantees) via different means, without creating a temporary.

+
+

reset

+
void reset();
+
+

Effects: Equivalent to weak_ptr().swap(*this).

+
+

get

+
T * get() const; // never throws
+
+

Returns: the stored pointer (0 if all shared_ptr objects for that + pointer are destroyed.)

+

Throws: nothing.

+

Notes: Using get in multithreaded code is dangerous. After the + function returns, the pointed-to object may be destroyed by a different thread, + since the weak_ptr doesn't affect its use_count.

+
+

use_count

+
long use_count() const; // never throws
+
+

Returns: the number of shared_ptr objects sharing ownership of the + stored pointer.

+

Throws: nothing.

+

Notes: use_count() is not necessarily efficient. Use only + for debugging and testing purposes, not for production code. T need not + be a complete type. See the smart pointer + common requirements.

+
+

expired

+
bool expired() const; // never throws
+
+

Returns: use_count() == 0.

+

Throws: nothing.

+

Notes: expired() may be faster than use_count(). + T need not be a complete type. See the smart pointer + common requirements.

+
+

swap

+
void swap(weak_ptr & b); // never throws
+
+

Effects: Exchanges the contents of the two smart pointers.

+

Throws: nothing.

+

Notes: T need not be a complete type. See the smart pointer + common requirements.

+
+

Free Functions

+

comparison

+
template<typename T, typename U>
+  bool operator==(weak_ptr<T> const & a, weak_ptr<U> const & b); // never throws
+template<typename T, typename U>
+  bool operator!=(weak_ptr<T> const & a, weak_ptr<U> const & b); // never throws
+
+

Returns: a.get() == b.get().

+

Throws: nothing.

+

Notes: T need not be a complete type. See the smart pointer + common requirements.

+
+
template<typename T>
+  bool operator<(weak_ptr<T> const & a, weak_ptr<T> const & b); // never throws
+
+

Returns: an implementation-defined value such that operator< is + a strict weak ordering as described in section 25.3 [lib.alg.sorting] + of the C++ standard.

+

Throws: nothing.

+

Notes: Allows weak_ptr objects to be used as keys in + associative containers. T need not be a complete type. See the smart + pointer common requirements.

+
+

swap

+
template<typename T>
+  void swap(weak_ptr<T> & a, weak_ptr<T> & b) // never throws
+
+

Effects: Equivalent to a.swap(b).

+

Throws: nothing.

+

Notes: Matches the interface of std::swap. Provided as an aid to + generic programming.

+
+

make_shared

+
template<typename T>
+  shared_ptr<T> make_shared(weak_ptr<T> & const r) // never throws
+
+

Returns: r.expired()? shared_ptr<T>(): shared_ptr<T>(r).

+

Throws: nothing.

+
+
+

Revised 12 March 2002

+

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.

+ + +