From 468c41041b3d7ec0394cea52e3c24b7ba90743f7 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 7 Jul 2000 16:04:40 +0000 Subject: [PATCH 001/133] This commit was generated by cvs2svn to compensate for changes in r4, which included commits to RCS files with non-trunk default branches. [SVN r7621] --- include/boost/smart_ptr.hpp | 369 ++++++++++++++++++++++++++++++++++++ smart_ptr_test.cpp | 263 +++++++++++++++++++++++++ 2 files changed, 632 insertions(+) create mode 100644 include/boost/smart_ptr.hpp create mode 100644 smart_ptr_test.cpp diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp new file mode 100644 index 0000000..e233104 --- /dev/null +++ b/include/boost/smart_ptr.hpp @@ -0,0 +1,369 @@ +// Boost smart_ptr.hpp header file -----------------------------------------// + +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. Permission to copy, +// use, modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided "as is" +// without express or implied warranty, and with no claim as to its +// suitability for any purpose. + +// See http://www.boost.org for most recent version including documentation. + +// Revision History +// 22 Jun 00 Remove #if continuations to fix GCC 2.95.2 problem (Beman Dawes) +// 1 Feb 00 Additional shared_ptr BOOST_NO_MEMBER_TEMPLATES workarounds +// (Dave Abrahams) +// 31 Dec 99 Condition tightened for no member template friend workaround +// (Dave Abrahams) +// 30 Dec 99 Moved BOOST_NMEMBER_TEMPLATES compatibility code to config.hpp +// (Dave Abrahams) +// 30 Nov 99 added operator ==, operator !=, and std::swap and std::less +// specializations for shared types (Darin Adler) +// 11 Oct 99 replaced op[](int) with op[](std::size_t) (Ed Brey, Valentin +// Bonnard), added shared_ptr workaround for no member template +// friends (Matthew Langston) +// 25 Sep 99 added shared_ptr::swap and shared_array::swap (Luis Coelho). +// 20 Jul 99 changed name to smart_ptr.hpp, #include , +// #include and use boost::noncopyable +// 17 May 99 remove scoped_array and shared_array operator*() as +// unnecessary (Beman Dawes) +// 14 May 99 reorder code so no effects when bad_alloc thrown (Abrahams/Dawes) +// 13 May 99 remove certain throw() specifiers to avoid generated try/catch +// code cost (Beman Dawes) +// 11 May 99 get() added, conversion to T* placed in macro guard (Valentin +// Bonnard, Dave Abrahams, and others argued for elimination +// of the automatic conversion) +// 28 Apr 99 #include fix (Valentin Bonnard) +// 28 Apr 99 rename transfer() to share() for clarity (Dave Abrahams) +// 28 Apr 99 remove unsafe shared_array template conversions(Valentin Bonnard) +// 28 Apr 99 p(r) changed to p(r.px) for clarity (Dave Abrahams) +// 21 Apr 99 reset() self assignment fix (Valentin Bonnard) +// 21 Apr 99 dispose() provided to improve clarity (Valentin Bonnard) +// 27 Apr 99 leak when new throws fixes (Dave Abrahams) +// 21 Oct 98 initial Version (Greg Colvin/Beman Dawes) + +#ifndef BOOST_SMART_PTR_HPP +#define BOOST_SMART_PTR_HPP + +#include // for broken compiler workarounds +#include // for std::size_t +#include // for std::auto_ptr +#include // for std::swap +#include // for boost::noncopyable +#include // for std::less + +namespace boost { + +// scoped_ptr --------------------------------------------------------------// + +// scoped_ptr mimics a built-in pointer except that it guarantees deletion +// of the object pointed to, either on destruction of the scoped_ptr or via +// an explicit reset(). scoped_ptr is a simple solution for simple needs; +// see shared_ptr (below) or std::auto_ptr if your needs are more complex. + +template class scoped_ptr : noncopyable { + + T* ptr; + + public: + typedef T element_type; + + explicit scoped_ptr( T* p=0 ) throw() : ptr(p) {} + ~scoped_ptr() { delete ptr; } + + void reset( T* p=0 ) { if ( ptr != p ) { delete ptr; ptr = p; } } + T& operator*() const throw() { return *ptr; } + T* operator->() const throw() { return ptr; } + T* get() const throw() { return ptr; } +#ifdef BOOST_SMART_PTR_CONVERSION + // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! + operator T*() const throw() { return ptr; } +#endif + }; // scoped_ptr + +// scoped_array ------------------------------------------------------------// + +// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to +// is guaranteed, either on destruction of the scoped_array or via an explicit +// reset(). See shared_array or std::vector if your needs are more complex. + +template class scoped_array : noncopyable { + + T* ptr; + + public: + typedef T element_type; + + explicit scoped_array( T* p=0 ) throw() : ptr(p) {} + ~scoped_array() { delete [] ptr; } + + void reset( T* p=0 ) { if ( ptr != p ) {delete [] ptr; ptr=p;} } + + T* get() const throw() { return ptr; } +#ifdef BOOST_SMART_PTR_CONVERSION + // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! + operator T*() const throw() { return ptr; } +#else + T& operator[](std::size_t i) const throw() { return ptr[i]; } +#endif + }; // scoped_array + +// shared_ptr --------------------------------------------------------------// + +// An enhanced relative of scoped_ptr with reference counted copy semantics. +// The object pointed to is deleted when the last shared_ptr pointing to it +// is destroyed or reset. + +template class shared_ptr { + public: + typedef T element_type; + + explicit shared_ptr(T* p =0) : px(p) { + try { pn = new long(1); } // fix: prevent leak if new throws + catch (...) { delete p; throw; } + } + + shared_ptr(const shared_ptr& r) throw() : px(r.px) { ++*(pn = r.pn); } + + ~shared_ptr() { dispose(); } + + shared_ptr& operator=(const shared_ptr& r) { + share(r.px,r.pn); + return *this; + } + +#if !defined( BOOST_NO_MEMBER_TEMPLATES ) + template + shared_ptr(const shared_ptr& r) throw() : px(r.px) { + ++*(pn = r.pn); + } + + template + shared_ptr(std::auto_ptr& r) { + pn = new long(1); // may throw + px = r.release(); // fix: moved here to stop leak if new throws + } + + template + shared_ptr& operator=(const shared_ptr& r) { + share(r.px,r.pn); + return *this; + } + + template + shared_ptr& operator=(std::auto_ptr& r) { + // code choice driven by guarantee of "no effect if new throws" + if (*pn == 1) { delete px; } + else { // allocate new reference counter + long * tmp = new long(1); // may throw + --*pn; // only decrement once danger of new throwing is past + pn = tmp; + } // allocate new reference counter + px = r.release(); // fix: moved here so doesn't leak if new throws + return *this; + } +#else + shared_ptr(std::auto_ptr& r) { + pn = new long(1); // may throw + px = r.release(); // fix: moved here to stop leak if new throws + } + + shared_ptr& operator=(std::auto_ptr& r) { + // code choice driven by guarantee of "no effect if new throws" + if (*pn == 1) { delete px; } + else { // allocate new reference counter + long * tmp = new long(1); // may throw + --*pn; // only decrement once danger of new throwing is past + pn = tmp; + } // allocate new reference counter + px = r.release(); // fix: moved here so doesn't leak if new throws + return *this; + } +#endif + + void reset(T* p=0) { + if ( px == p ) return; // fix: self-assignment safe + if (--*pn == 0) { delete px; } + else { // allocate new reference counter + try { pn = new long; } // fix: prevent leak if new throws + catch (...) { + ++*pn; // undo effect of --*pn above to meet effects guarantee + delete p; + throw; + } // catch + } // allocate new reference counter + *pn = 1; + px = p; + } // reset + + T& operator*() const throw() { return *px; } + T* operator->() const throw() { return px; } + T* get() const throw() { return px; } + #ifdef BOOST_SMART_PTR_CONVERSION + // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! + operator T*() const throw() { return px; } + #endif + + long use_count() const throw(){ return *pn; } + bool unique() const throw() { return *pn == 1; } + + void swap(shared_ptr& other) throw() + { std::swap(px,other.px); std::swap(pn,other.pn); } + +// Tasteless as this may seem, making all members public allows member templates +// to work in the absence of member template friends. (Matthew Langston) +// Don't split this line into two; that causes problems for some GCC 2.95.2 builds +#if defined(BOOST_NO_MEMBER_TEMPLATES) || !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) + private: +#endif + + T* px; // contained pointer + long* pn; // ptr to reference counter + +// Don't split this line into two; that causes problems for some GCC 2.95.2 builds +#if !defined( BOOST_NO_MEMBER_TEMPLATES ) && !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) + template friend class shared_ptr; +#endif + + void dispose() { if (--*pn == 0) { delete px; delete pn; } } + + void share(T* rpx, long* rpn) { + if (pn != rpn) { + dispose(); + px = rpx; + ++*(pn = rpn); + } + } // share +}; // shared_ptr + +template + inline bool operator==(const shared_ptr& a, const shared_ptr& b) + { return a.get() == b.get(); } + +template + inline bool operator!=(const shared_ptr& a, const shared_ptr& b) + { return a.get() != b.get(); } + +// shared_array ------------------------------------------------------------// + +// shared_array extends shared_ptr to arrays. +// The array pointed to is deleted when the last shared_array pointing to it +// is destroyed or reset. + +template class shared_array { + public: + typedef T element_type; + + explicit shared_array(T* p =0) : px(p) { + try { pn = new long(1); } // fix: prevent leak if new throws + catch (...) { delete [] p; throw; } + } + + shared_array(const shared_array& r) throw() : px(r.px) { ++*(pn = r.pn); } + + ~shared_array() { dispose(); } + + shared_array& operator=(const shared_array& r) { + if (pn != r.pn) { + dispose(); + px = r.px; + ++*(pn = r.pn); + } + return *this; + } // operator= + + void reset(T* p=0) { + if ( px == p ) return; // fix: self-assignment safe + if (--*pn == 0) { delete [] px; } + else { // allocate new reference counter + try { pn = new long; } // fix: prevent leak if new throws + catch (...) { + ++*pn; // undo effect of --*pn above to meet effects guarantee + delete [] p; + throw; + } // catch + } // allocate new reference counter + *pn = 1; + px = p; + } // reset + + T* get() const throw() { return px; } + #ifdef BOOST_SMART_PTR_CONVERSION + // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! + operator T*() const throw() { return px; } + #else + T& operator[](std::size_t i) const throw() { return px[i]; } + #endif + + long use_count() const throw() { return *pn; } + bool unique() const throw() { return *pn == 1; } + + void swap(shared_array& other) throw() + { std::swap(px,other.px); std::swap(pn,other.pn); } + + private: + + T* px; // contained pointer + long* pn; // ptr to reference counter + + void dispose() { if (--*pn == 0) { delete [] px; delete pn; } } + +}; // shared_array + +template + inline bool operator==(const shared_array& a, const shared_array& b) + { return a.get() == b.get(); } + +template + inline bool operator!=(const shared_array& a, const shared_array& b) + { return a.get() != b.get(); } + +} // namespace boost + +// specializations for things in namespace std -----------------------------// + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +namespace std { + +// Specialize std::swap to use the fast, non-throwing swap that's provided +// as a member function instead of using the default algorithm which creates +// a temporary and uses assignment. + +template + inline void swap(boost::shared_ptr& a, boost::shared_ptr& b) + { a.swap(b); } + +template + inline void swap(boost::shared_array& a, boost::shared_array& b) + { a.swap(b); } + +// Specialize std::less so we can use shared pointers and arrays as keys in +// associative collections. + +// It's still a controversial question whether this is better than supplying +// a full range of comparison operators (<, >, <=, >=). + +template + struct less< boost::shared_ptr > + : binary_function, boost::shared_ptr, bool> + { + bool operator()(const boost::shared_ptr& a, + const boost::shared_ptr& b) const + { return less()(a.get(),b.get()); } + }; + +template + struct less< boost::shared_array > + : binary_function, boost::shared_array, bool> + { + bool operator()(const boost::shared_array& a, + const boost::shared_array& b) const + { return less()(a.get(),b.get()); } + }; + +} // namespace std + +#endif // ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +#endif // BOOST_SMART_PTR_HPP + diff --git a/smart_ptr_test.cpp b/smart_ptr_test.cpp new file mode 100644 index 0000000..cd4d61b --- /dev/null +++ b/smart_ptr_test.cpp @@ -0,0 +1,263 @@ +// 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 +// 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 +#include + +#ifdef NDEBUG +#error This test program makes no sense if NDEBUG is defined +#endif + +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 ) { assert( *v1 == v2 ); } + +namespace { + int UDT_use_count; // independent of pointer maintained counts + } + +// user defined type -------------------------------------------------------// + +class UDT { + long value_; + public: + explicit UDT( long value=0 ) : value_(value) { ++UDT_use_count; } + ~UDT() { + --UDT_use_count; + cout << "UDT with value " << value_ << " being destroyed" << endl; + } + long value() const { return value_; } + void value( long v ) { value_ = v;; } + }; // UDT + +// main --------------------------------------------------------------------// + +// This isn't a very systematic test; it just hits some of the basics. + +int main() { + + assert( UDT_use_count == 0 ); // reality check + + // test scoped_ptr with a built-in type + long * lp = new long; + scoped_ptr sp ( lp ); + assert( sp.get() == lp ); + assert( lp == sp.get() ); + assert( &*sp == lp ); + + *sp = 1234568901L; + assert( *sp == 1234568901L ); + assert( *lp == 1234568901L ); + ck( static_cast(sp.get()), 1234568901L ); + ck( lp, *sp ); + + sp.reset(); + assert( sp.get() == 0 ); + + // test scoped_ptr with a user defined type + scoped_ptr udt_sp ( new UDT( 999888777 ) ); + assert( udt_sp->value() == 999888777 ); + udt_sp.reset(); + udt_sp.reset( new UDT( 111222333 ) ); + assert( udt_sp->value() == 111222333 ); + udt_sp.reset( new UDT( 333222111 ) ); + assert( udt_sp->value() == 333222111 ); + + // test scoped_array with a build-in type + char * sap = new char [ 100 ]; + scoped_array sa ( sap ); + assert( sa.get() == sap ); + assert( sap == sa.get() ); + + strcpy( sa.get(), "Hot Dog with mustard and relish" ); + assert( strcmp( sa.get(), "Hot Dog with mustard and relish" ) == 0 ); + assert( strcmp( sap, "Hot Dog with mustard and relish" ) == 0 ); + + assert( sa[0] == 'H' ); + assert( sa[30] == 'h' ); + + sa[0] = 'N'; + sa[4] = 'd'; + assert( strcmp( sap, "Not dog with mustard and relish" ) == 0 ); + + sa.reset(); + assert( sa.get() == 0 ); + + // test shared_ptr with a built-in type + int * ip = new int; + shared_ptr cp ( ip ); + assert( ip == cp.get() ); + assert( cp.use_count() == 1 ); + + *cp = 54321; + assert( *cp == 54321 ); + assert( *ip == 54321 ); + ck( static_cast(cp.get()), 54321 ); + ck( static_cast(ip), *cp ); + + shared_ptr cp2 ( cp ); + assert( ip == cp2.get() ); + assert( cp.use_count() == 2 ); + assert( cp2.use_count() == 2 ); + + assert( *cp == 54321 ); + assert( *cp2 == 54321 ); + ck( static_cast(cp2.get()), 54321 ); + ck( static_cast(ip), *cp2 ); + + shared_ptr cp3 ( cp ); + assert( cp.use_count() == 3 ); + assert( cp2.use_count() == 3 ); + assert( cp3.use_count() == 3 ); + cp.reset(); + assert( cp2.use_count() == 2 ); + assert( cp3.use_count() == 2 ); + assert( cp.use_count() == 1 ); + cp.reset( new int ); + *cp = 98765; + assert( *cp == 98765 ); + *cp3 = 87654; + assert( *cp3 == 87654 ); + assert( *cp2 == 87654 ); + cp.swap( cp3 ); + assert( *cp == 87654 ); + assert( *cp2 == 87654 ); + assert( *cp3 == 98765 ); + cp.swap( cp3 ); + assert( *cp == 98765 ); + assert( *cp2 == 87654 ); + assert( *cp3 == 87654 ); + cp2 = cp2; + assert( cp2.use_count() == 2 ); + assert( *cp2 == 87654 ); + cp = cp2; + assert( cp2.use_count() == 3 ); + assert( *cp2 == 87654 ); + assert( cp.use_count() == 3 ); + assert( *cp == 87654 ); + + shared_ptr cp4; + swap( cp2, cp4 ); + assert( cp4.use_count() == 3 ); + assert( *cp4 == 87654 ); + assert( cp2.get() == 0 ); + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + set< shared_ptr > scp; + scp.insert(cp4); + assert( scp.find(cp4) != scp.end() ); + assert( scp.find(cp4) == scp.find( shared_ptr(cp4) ) ); +#endif + + // test shared_array with a built-in type + char * cap = new char [ 100 ]; + shared_array ca ( cap ); + assert( ca.get() == cap ); + assert( cap == ca.get() ); + assert( &ca[0] == cap ); + + strcpy( ca.get(), "Hot Dog with mustard and relish" ); + assert( strcmp( ca.get(), "Hot Dog with mustard and relish" ) == 0 ); + assert( strcmp( cap, "Hot Dog with mustard and relish" ) == 0 ); + + assert( ca[0] == 'H' ); + assert( ca[30] == 'h' ); + + shared_array ca2 ( ca ); + shared_array ca3 ( ca2 ); + + ca[0] = 'N'; + ca[4] = 'd'; + assert( strcmp( ca.get(), "Not dog with mustard and relish" ) == 0 ); + assert( strcmp( ca2.get(), "Not dog with mustard and relish" ) == 0 ); + assert( strcmp( ca3.get(), "Not dog with mustard and relish" ) == 0 ); + assert( ca.use_count() == 3 ); + assert( ca2.use_count() == 3 ); + assert( ca3.use_count() == 3 ); + ca2.reset(); + assert( ca.use_count() == 2 ); + assert( ca3.use_count() == 2 ); + assert( ca2.use_count() == 1 ); + + ca.reset(); + assert( ca.get() == 0 ); + + shared_array ca4; + swap( ca3, ca4 ); + assert( ca4.use_count() == 1 ); + assert( strcmp( ca4.get(), "Not dog with mustard and relish" ) == 0 ); + assert( ca3.get() == 0 ); + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + set< shared_array > sca; + sca.insert(ca4); + assert( sca.find(ca4) != sca.end() ); + assert( sca.find(ca4) == sca.find( shared_array(ca4) ) ); +#endif + + // 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 ); + + assert( udta[0].value() == 111 ); + assert( udta[1].value() == 222 ); + assert( udta[2].value() == 333 ); + assert( udta2[0].value() == 111 ); + assert( udta2[1].value() == 222 ); + assert( udta2[2].value() == 333 ); + udta2.reset(); + assert( udta2.get() == 0 ); + assert( udta.use_count() == 1 ); + assert( udta2.use_count() == 1 ); + + assert( UDT_use_count == 4 ); // reality check + + // test shared_ptr with a user defined type + UDT * up = new UDT; + shared_ptr sup ( up ); + assert( up == sup.get() ); + assert( sup.use_count() == 1 ); + + sup->value( 54321 ) ; + assert( sup->value() == 54321 ); + assert( up->value() == 54321 ); + + shared_ptr sup2; + sup2 = sup; + assert( sup2->value() == 54321 ); + assert( sup.use_count() == 2 ); + assert( sup2.use_count() == 2 ); + sup2 = sup2; + assert( sup2->value() == 54321 ); + assert( sup.use_count() == 2 ); + assert( sup2.use_count() == 2 ); + + cout << "OK" << endl; + + new char[12345]; // deliberate memory leak to verify leaks detected + + return 0; + } // main + From 90b7ec19d115aa2a27a8d3c3fdbe620fbb002bd4 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Mon, 24 Jul 2000 16:21:10 +0000 Subject: [PATCH 002/133] Changed throw() to // never throws. [SVN r7628] --- include/boost/smart_ptr.hpp | 53 ++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp index e233104..353e472 100644 --- a/include/boost/smart_ptr.hpp +++ b/include/boost/smart_ptr.hpp @@ -9,6 +9,8 @@ // See http://www.boost.org for most recent version including documentation. // Revision History +// 24 Jul 00 Change throw() to // never throws. See lib guidelines +// Exception-specification rationale. (Beman Dawes) // 22 Jun 00 Remove #if continuations to fix GCC 2.95.2 problem (Beman Dawes) // 1 Feb 00 Additional shared_ptr BOOST_NO_MEMBER_TEMPLATES workarounds // (Dave Abrahams) @@ -67,16 +69,16 @@ template class scoped_ptr : noncopyable { public: typedef T element_type; - explicit scoped_ptr( T* p=0 ) throw() : ptr(p) {} + explicit scoped_ptr( T* p=0 ) : ptr(p) {} // never throws ~scoped_ptr() { delete ptr; } void reset( T* p=0 ) { if ( ptr != p ) { delete ptr; ptr = p; } } - T& operator*() const throw() { return *ptr; } - T* operator->() const throw() { return ptr; } - T* get() const throw() { return ptr; } + T& operator*() const { return *ptr; } // never throws + T* operator->() const { return ptr; } // never throws + T* get() const { return ptr; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! - operator T*() const throw() { return ptr; } + operator T*() const { return ptr; } // never throws #endif }; // scoped_ptr @@ -93,17 +95,17 @@ template class scoped_array : noncopyable { public: typedef T element_type; - explicit scoped_array( T* p=0 ) throw() : ptr(p) {} + explicit scoped_array( T* p=0 ) : ptr(p) {} // never throws ~scoped_array() { delete [] ptr; } void reset( T* p=0 ) { if ( ptr != p ) {delete [] ptr; ptr=p;} } - T* get() const throw() { return ptr; } + T* get() const { return ptr; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! - operator T*() const throw() { return ptr; } + operator T*() const { return ptr; } // never throws #else - T& operator[](std::size_t i) const throw() { return ptr[i]; } + T& operator[](std::size_t i) const { return ptr[i]; } // never throws #endif }; // scoped_array @@ -122,7 +124,7 @@ template class shared_ptr { catch (...) { delete p; throw; } } - shared_ptr(const shared_ptr& r) throw() : px(r.px) { ++*(pn = r.pn); } + shared_ptr(const shared_ptr& r) : px(r.px) { ++*(pn = r.pn); } // never throws ~shared_ptr() { dispose(); } @@ -133,7 +135,7 @@ template class shared_ptr { #if !defined( BOOST_NO_MEMBER_TEMPLATES ) template - shared_ptr(const shared_ptr& r) throw() : px(r.px) { + shared_ptr(const shared_ptr& r) : px(r.px) { // never throws ++*(pn = r.pn); } @@ -195,18 +197,18 @@ template class shared_ptr { px = p; } // reset - T& operator*() const throw() { return *px; } - T* operator->() const throw() { return px; } - T* get() const throw() { return px; } + T& operator*() const { return *px; } // never throws + T* operator->() const { return px; } // never throws + T* get() const { return px; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! - operator T*() const throw() { return px; } + operator T*() const { return px; } // never throws #endif - long use_count() const throw(){ return *pn; } - bool unique() const throw() { return *pn == 1; } + long use_count() const { return *pn; } // never throws + bool unique() const { return *pn == 1; } // never throws - void swap(shared_ptr& other) throw() + void swap(shared_ptr& other) // never throws { std::swap(px,other.px); std::swap(pn,other.pn); } // Tasteless as this may seem, making all members public allows member templates @@ -258,7 +260,8 @@ template class shared_array { catch (...) { delete [] p; throw; } } - shared_array(const shared_array& r) throw() : px(r.px) { ++*(pn = r.pn); } + shared_array(const shared_array& r) : px(r.px) // never throws + { ++*(pn = r.pn); } ~shared_array() { dispose(); } @@ -286,18 +289,18 @@ template class shared_array { px = p; } // reset - T* get() const throw() { return px; } + T* get() const { return px; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! - operator T*() const throw() { return px; } + operator T*() const { return px; } // never throws #else - T& operator[](std::size_t i) const throw() { return px[i]; } + T& operator[](std::size_t i) const { return px[i]; } // never throws #endif - long use_count() const throw() { return *pn; } - bool unique() const throw() { return *pn == 1; } + long use_count() const { return *pn; } // never throws + bool unique() const { return *pn == 1; } // never throws - void swap(shared_array& other) throw() + void swap(shared_array& other) // never throws { std::swap(px,other.px); std::swap(pn,other.pn); } private: From ed7e13da9f2d7ea2878e0bac3627d7271ab52b07 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 27 Jul 2000 14:18:23 +0000 Subject: [PATCH 003/133] Initial commit [SVN r7638] --- gccspeed.gif | Bin 0 -> 6603 bytes msvcspeed.gif | Bin 0 -> 6169 bytes smarttest.zip | Bin 0 -> 11513 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 gccspeed.gif create mode 100644 msvcspeed.gif create mode 100644 smarttest.zip diff --git a/gccspeed.gif b/gccspeed.gif new file mode 100644 index 0000000000000000000000000000000000000000..d78c06bbf8b6b72380950b597c32ada51e5186b6 GIT binary patch literal 6603 zcmZ?wbh9u|G+;_*{LTOZ#taN;3=A_F7|t*-{AXZbFlI0|W=Jz;m}$&##+czhSlT#^ zAuWwzW*WnpG=~3R)y6X!(q=NuoXK!zCc}TQX5%vqX=fN_o?$q1hT%WhEaU$SY5y5! z{%1JzpW#2)Xk!NBGzR0D48~^|jQ@jeGB!3&Gd7-SY<$Mp_&?ZU<22*6G~=0R#%I!u z|AXCOJkvOBrt!>~#%E?4{|7tE_>6Jd8RMB}jL)1g{ttGg@qgpA|Hd=_8=v`a{2%OS zV~~^6W`Z1*_Mah*0c1~F8px!yGa$7fFBzwSz|6F?Giho6!9FyenU*#)ZRX6hGc(iv zgFS3~1|&W6Oxl?T=@jGmb`^Gw>z|KPAQo(ZyP=FFLAX3qQ%4oc%QAd6?7nR({S%>Uq!HU1BB z$ISmT&-|bH9~{ueph!3~6BNv6{xh6m0EOI{G*H-_IRo-NC>o4G9s-$l2INLitQdo= zJu?$z@R|SMNHRVH^3u#RAn+d?XU6|QKAidg%$fgZ{)3~?7!=$8XM*DM|9^)644^3b zp9YGA|7SqK42oc5P{@H?c?J|1p!hZh`S1TskPrU<2S>m08Bk!&JOeWNKR7iQ{|ANL z%>N*p{(}<-C@s<*EB<5w+o=O0L3zS~<3GcCP8p943l27O2y4Zh*s$<$yMVIS9FL8Q zj&@5JXWcomaq;nf1?Mgq&rKu6gE|wFPI!xCM-WMYIS>a5!UjDNsD<`Y_&e2R| za^)yaKReT-UG8n>h8O-z&HK%2vo@`|x;kQW*4;C@*wfqA z-ripD_|#nQ?d$IDuK4`w?&6)~ z`(5V##ovEO8U8xD_vZ4e`qTIS{x9k4em8cfh{XhU&Y#;aMz(1FnAXg&i(S5vP3#F{ z6aUHbxE9WTtcvX`0?il3ib|C%^pLVTam+d7srmhG>08?$7Vf?}V_vUulltOplVcTg zsx14yD|XcPMua!+R4GY{$}#a2nK084_(o2h z`8zQ3X+vS+$|sXzOCv8$&-&kVTzpokl*)sNo@Ol1!-{sfrq8Qzt5oi@yCr!!^%Uoe z7mFuE&73})>u+Yzf)-w@fF*OvZY3@<-X)P7kSL|Ks;6V3RMyH`QK{)mR;YSrPK%z@ zqM0*m)l04L-D#|^(>>f$Ub^|N<49U3Gxd7p`Y6NOg0ttcYUixw7hRoZaD#2K;3n>S z(?#;9w`Qv^POy}IQuA!-?s;L=LTxGY1u{7&ZoQS-y*B2KQ0BYPGyklnZxQ94EwJ~% z&C^l)B)7iM4f!$C{QAByN1khIxHUosqoR ze_FTR`!nY6|Nr@X!Cn9Fm#2@WWd-qQFTL^g)_WJdZ}(PLO$&a&?f>`Zi{(vIh*#sWi)8u{UiVF zjr&2as1HpNXBM!TpE$@@^`Ti|4#y4w*Ugu01sEDV7IKB3I3%{~L#sj0LY{Pw!&0|C zv{{^4$X9;iu-vZ??GA4eIc}S|e0{sNLujSE(Cy+Qs+&%9Udc}S+~a=q=}n!=fS!3G zn}0~_nXR|J@F_{?sK?ea-<0kYl{l%TkJtC-oK5}EJxNIWk=C6R9|J0E=H0(`L(=%r z)83MhD=$B6-q2pz(O>yddH#c^wkEq6H`x}KNGjdDdTjd{uN=v$*zFdRB^f52tT2cY zxpeNaZQwPQDUCG?w8UA>zqx#B>RQ5mqr`2yWoA+4>Hn8HIK6)?e)zU<64S~jQM0yf zw)px+s-Ne)cCe+3VCzNQ%{q~~8=1Ctt9+KaY$DRf!KoZ_?9GH%-Kr+DuX*UnUe>yP zSS?r~sF7a+I_FUQVZ{MBR|IP4JDaYS?`oA@N z5)3y5{rJ;ir+WDOE~W z`*>WCDq0oz@2%S+r|z9T%uD9|`n-If)ymzkG8cBtTeI}y#@U`Ow`3-DZBUWgD-?J? zC8V)oi<#F~?%?Z>cNxAqx-xEVhsAA`)eVW06g=jh@m|0As-Bq9a?7RMJ0t!}&RDr> ziemWO?kgvr?b)W39$#3SuF=@Fx!p-*y?pEGsLe0Jbsia-x9+*@y8cjL)F&S8Zq{Wt z*`{x6G1+EOJT=z+#LA^x!dlipf4t_ZL$jO9te1 zh-PeA%5l%+^n_EA=7on9*WJ-kvTTwGFFG5VmtC~`*affe##ek7m#)7(^G)7`mNj!` zRvh=f_i5JmJuiIMS6x4S@7u2Ldq4E9uX*kr|E=izz8|kk1MK z3TK=DNv>-?j0?{s$-NFgaVL2O(@Y~#cD;hr%03C*orm^naZflM^X=30{4>wYqG$G4 z=LO7ozCBH_>BrfMbDQUVKl9w~_s{bUd|MW<`@V3J{&k_lZ_A>&kNp|tD=tp(yS!t~ ziws*KlS@ZGu9JA*lesqIR`;BDCSi8}&mIlvmYS<*_I2g-S+7Fdr__Fpe0n=YHaL87 z+m*%K8KT+S?t9;^+O^?W($dVZ*YW*q*8@VfZgf-%d8buwCa^t@8ofBGyfF%P{d1pZ_9Jht&;CnyOdfU71Kx*@0xDKWqr4QURT@g-ihVm ztdZ}zb{t@jQ%YSpY4)~@PdS4{w{v`-c3^T1Of^h2PM}KGP zY&W;_6L#Hlr)S!v)t>jJW&FFQs39+Rq{1p;*QG7bIQ_RAQBRAg4ii0K6w`SM-kCL@udOw@ z_wz_~+_@)KVc}f!P1c{4+wo^rtoGF0-ImGOr8oaK$h=J1vpe+Dy7FYMyPH3zJv-|v zJ$?UwS%)Tb&WE*q)AkrWnPq=H*_U1NCc9;AbArn1`9}6am&2C4w@*{QVegrJe)XOv zo##JaXxIO!SHEZ5w><96^>-7dM<4yPqRx8iwUrO@-|2k{Ra|Sklc{FQ0=usk^%mjg z>F)ka{~qpE-S(l?%zw{~sb8cr?PBNIKgu_K6TrTI`z67BUz*rX9ydGxeZx}uMR&d1 zR_r^U{#LQMDt7AkKpY6W?rJgS}2%v9AAP&8N0P5f6z#b1Ak% zWv-z@0u?#i**)i9&)sMk+In5^+NS!mij8X~R(D>JQn}&5w?aVn35RT?X#}UT8jFe= zn}*&Bp>zSY$l}7r{*O&l%msB?o8ARBa~1j;Z;kOv5578G!hLyg+{J>;&k8b@i#c&f zOjh?5GHgD!uw}{S+FwpCj~32?L$rOd zVf&6xR@+RwwtrP}{oZ2sLTs9ZWZnwZCG2grj9oq<9j`>1Y8{(G+Qa&07)_XAt~Eny z^^01mjG}@U;`WzYqFlPK|5r3jZfd_+UVGT2M_Qx#IzxB3Vz-n^XVwjc@{ES`>)E^} zKKzZIyDfyOw;IlB)j9t)#;mk;r(>Dujb3}V?4#zLQ&fBNI|Qy(2;P_xKi4&1L8wQ0 zVU7FK&cMsv@+r|OAG=p5PLK-p_YUe4a5OuSVc#q)p&1k}wR57(%D8PBfzAk_9)bpvLPnjUwweM}KVT`1?z|_f(|5B%{Ea zSv+p$H2;+XsW-zPxC!RooKpW~T9K)zq_d<`fB1CX!s!ZArdLJEmi(Ol=eT?3kDjKV z;x(Oit(H^wOlny6xN6ml8SR!cr$o-2Ryp(kjLO0gNyD!lHbvJH9=f)^em3*rjTwtA zJ-Z_%+bY!#2HUKCIdlF@QHE_ZKdq>pSvh;h%-Oqk&far#_P(7uA!2b{PwK?XQtvA} zI*QHWo<3*k&)Lt5)3l~FN4U+o*eUtNw}U zm^ts&&Ux~iwF_P51#L|JV3{UsIR8zgxbU*M-fngr79z(zlm2z420wEMnr6%7CHDD+ zrzV?ud|Ogv+5FanN$j(1pM77j%w*xcNQa-n3%{&Pz2>=4YSsLB!7?STw8NS61#VTi zZCkj~e9rC8w8SeyifeAxwYhGq7R0NU zJ+EAPmAU6{a=EXTl~paTn60yH*=qU%juY@_^JDZ;LfYX5}8MT4NwO z?bIyKGq=`M@3iCADxa~cXWy*VGLP$1m*-vEwfcsa2J5!9KiyKcTg|*5rOu;n=jyrY zg4EheuOeKxEsMOdj=gZ5c*wf;%=Ka|>+3V?TRhjZCc6EKa{QB(n{2v4BxHlOx(`RT zJ(qN*(De-mpRM>8wf^L<<)Yj(Qm##uxxG>L_r#i69j8y_9sbY0sZ49rQLi>e$?}L9 z3&MYFy8CLj#_!cy)y+Mb{g&zhD|fA1UA0{Dw&1N3T0Gl*HKYu6qP134P0{?dS+USp zF|#>Eyw&{o3^VTlPwT1tt0RrQ^ICswIi4*4vOKt`bjz&co4vF*M_U^idIu}dn%f_` zWzEm39VfSRRq#qh6i#_K;cr*x%o~Mblehj!+N3;vo8m*YqemtzU%35(+YSXo?|tn% zmMq+{+--Z;i|wJTI~ObN>~`B3S?I~2;OVdD?`OMl*-SW6a!BZDhxwb9Mba~^d0cIEgw$;I%P@93+i1NoZ+OaS z<9^5IbF}dM9wUC{8)DbN11woF+C;LI0SNx6!-z z2Or%aa#(?LqK{0SkmqWCo~XOpwpnv_Z{A)W-netY!krhIk1J$uSG;-5_s=ok-^ZVc zo!D{sL}g5v=;q@R7mw$;oYWNWk1shIai@CDpN2^`Sqpe%cCl?&VcenSdTMFRiH1if zx2Yf4;l4mGO>D}oO$)8JRvMpZ{e5D>o}k||M4fGRPq8SQVxhOhX(?*T zcBh<*EIf10{A{yo>#^HCw>me^eRWn|>fFDThuB!pDel>?&8&G)rRQ-7AGni4Oz9{tn0&8DvPMBA;d^MO59%PlVc&e{6h z?BFGz3t|yxXT%h3i4o=Q6<<)@_Jik~T3gcUE6q{QH#MbXHAq)&y4Vmdc&VoG#MwRK zYrmXcWGN||>*+uHLc@$xlM^q`TX>@S;^m<4mp|1Qn)sf-(<3|0N8CfU_v4vHr@2xt zz6Tba5#MAJa%j`Ra9Qcdx!eB->gFlG*s3aVQs&bU)|y?>x>sY*wr0e(OuTa?;_H=D zPS?tK#Dn*W#(MNDUvrkVxTk`*A^Q0FppMcFzfYyghAjVh{c?n$JBR9D4S^Gj3}?)} zIb-hLx4TQd-5u85xfZV~UTa&S?{WB-#*K)jQ%r6jEPQ^xBer2nW?=PQ(WPfiihZy1 zGDauPl?i*fX5HRRcW2aweYqkie*OQW6Pim8s!J$NjV(QPSIYXSpF&J|LgSqxL7j}= zTf1)DZr(e&UFNR#4YPy0&rJ(EnB8&LZtm?nwgRhorS{9#9Nc?|S?9vzRTrfd&rF?t zJ5#s0?5^ZTUa{ob{Ss-dI%_Y-7T*?Qys7$l(ixw(cb5o0SlxVoYs78FMfYMhc1}qT zc|X@sC{EnmM)iE!6~ToMX66XKjqUxfD{ReSg6GoC)4tNdbulZ`VS$m%G*Tv9A@a17M{Rf5TK&5I(7z8#7QT3+{OZ@uK8wG06J76ozO{YjIpcYJLX-KNu8U0n zwJe~Mw?AW#=jOP(RWlxXoxPI1@pVsV$G*I+%s=`TFehHjxhwqrqR!0M`X_IF7kx5c zYIn+`eO3D|Kk$ya+46$-;H#t~k<5WF1+Cr*8y>#g@{VKSJ1Lj0mSn+q=Xyi;2|kMx z_+lq;#?MjxWoE^_2_M!82+VwTEAIUrzYivr;=k8fa^?%<^eBA!_u-20N58*o_psoZQ=j4x z`)TXasFN=~a_z1Eto>!4VVAtg=U11tmz4L3{uKNX_cg5l{iUa0QdjJkw7vgv(mN5) zuaQ5epZEKGweHOgonR|_LBsdySwFvZ6bq!zw_6%Fx~9_!Kx-Pa-+ z{LE*TDetT;D}~a}O|%aDl=4D2ZzH!_oYr%FS(bHgXQc0|Ug?Mr35QyF<=y5) zd`vplD{J2-6Zt9S)KuO0V{;-ur=6Q?ThAsN^(EudQs4P*bECdyU0WNwzfCs!Th6Vm zx%ZE)HT|AZAZ?CEinYJNO<-oO6)zq!9_e(m14{d?bBtDm!vUH-rQo#h{!Z*;G> zV-;`FJ@90Pa)AZ&+G+tO_UVf^9AXme`e5@^g2nL2op+Nbtk`W~Be+t;HD#mgO^=fE XE|U^`I^D$cj~KekmiOo=FjxZs3WTu? literal 0 HcmV?d00001 diff --git a/msvcspeed.gif b/msvcspeed.gif new file mode 100644 index 0000000000000000000000000000000000000000..56295ee9a506c65a672bf105bb1a0f357377f579 GIT binary patch literal 6169 zcmZ?wbh9u|G+;_*{LTOZ#taN;3=A_F7|t*-{AXZbFlI0|W=Jz;m}$&##+czhSlT#^ zAuWwzW*WnpG=~3R)y6X!(q=NuoXK!zCc}TQX5%vqX=fN_o?$q1hT%WhEaU$SY5y5! z{%1JzpW#2)Xk!NBGzR0D48~^|jQ@jeGB!3&Gd7-SY<$Mp_&?ZU<22*6G~=0R#%I!u z|AXCOJkvOBrt!>~#%E?4{|7tE_>6Jd8RMB}jL)1g{ttGg@qgpA|Hd=_8=v`a{2%OS zV~~^6W`Z1*_Mah*0c1~F8px!yGa$7fFBzwSz|6F?Giho6!9FyenU*#)ZRX6hGc(iv zgFS3~1|&W6Oxl?T=@jGmb`^Gw>z|KPAQo(ZyP=FFLAX3qQ%4oc%QAd6?7nR({S%>Uq!HU1BB z$ISmT&-|bH9~{ueph!3~6BNv6{xh6m0EOI{G*H-_IRo-NC>o4G9s-$l2INLitQdo= zJu?$z@R|SMNHRVH^3u#RAn+d?XU6|QKAidg%$fgZ{)3~?7!=$8XM*DM|9^)644^3b zp9YGA|7SqK42oc5P{@H?c?J|1p!hZh`S1TskPrU<2S>m08Bk!&JOeWNKR7iQ{|ANL z%>N*p{(}<-C@s<*EB<5w+o=O0L3zS~<3GcCP8p943l27O2y4Zh*s$<$yMVIS9FL8Q zj&@5JXWcomaq;nf1?Mgq&rM4_7&HR;LNq5lHJz>*yp6@-LaOg9?ZR6rCxxG%nQxr@ z>Pw`+vkP-P;^lmIP1Xol>ba0DS8Hol;BvLiS$9uuU44Ch!r?Ai?`>;tZqB&8D)#iY zwYRqyJU%tod;7Y(yDL7wx_f&2`uqDE9{y5UwK>iEaHFtx+?gF4lh*Vpd(YD`5O{i8 zQZf178O!xg&n=M6;`7~Aa_juE;PoMAcWsThvhJ#o-JV~nk8X0gAHR3DTKUbr*`>_# zet&MYKIWx0XDh2LW<5)2Zp}T<+aHio z`gKQP^K-xWCEpKR$-HiVA};6u-@SLsXR^!bOqpM$u(Ld{^6gEROO=Ix*%yT0^E7|x z$l_-n-{i_TRjy|1(&NJQR~<8wI#ge=FH8_mQ%&e*6O35kvGdA}3yng2)0I0dO`j$g zTfa+v=x|Xq^T`BZ*-n`r&XYF+d(CFGBzr{YswQ=PV9lH~twWJRsq6j68`rvh&OJ?W z3Fu3|J|*?Pm8r;d*@KdTlT!DEKA6enC@Cdfv*}{o+&nJTH|6Wg z%AuC*r63~Jg%#WsXDIk z`=YUW?KZXC^sDEjw9?F0tqj6=Hy+ThrBv4bpMZ>sFh@m+0jxXRM!#ojY>t%Z)&Y&#v$ z7Il!js8A{0ZIjouPh0id#cEq`3!E0M{qw1nl|}c<1sCyx2^S|CRes(mURcw6K1(rH zes9R-=#mR8o^S6o+J~#$Uz^~(Ea7^}|D&ZhGj)5v-8#DI?4sKRmrKj;{JWU@J-Yb* z-iz0hUcKEOS@~c0$AcE}ydMucULXA)ndSba^f9j@_qE5R>ay3`8P(VQd^YEQ`MaOb z7Z|@u2(>j#jhou6>ssaWVyRu|+Qs&vzk(ND&-?v$hp?U5SzBKp!}rPmT{a#u=j6A3 z?I`;H@ylcTGj|2?of4^jdHi=?NXUiV^L~Hhe!K4Pt3A=Ie?uR~yG{*tTWV)m@o@b= zn_v67-#`5R(%s(b)2HI~|Ns5@{{H`e2A%~B>>dZ0X0;W?9hy_1knZ5Zx~_3s(}QPn z9FA;W0&XHX3t06l7V=#3&G~;Ql!f)!!6TI$8l-g+YfmgWq_?#oT&Ly)C+Cbq;*V6@ zR6A#$al2uAbmp11Ud^D`k{L69&-9PqIN5hU!!n0xU4f2*gNaE-PfX;PR!R%$8~wbKB+mOh(h<+oH2R-E$3w1B*xjYp zP`Pvshu~%pr%9d1bYrv@a~!_rystp8sd$ZtLcH*?y)UzZO%IDJ)k}zJN`2^OpSk3w zR^`#z9{K%kJSSKDOV?`dc^*F9P(ngie7T2Vf5{G?I7Q#irP2TTv_h5U3t4aSI@|b3 zYS9z!Ek}%WqNcG;lp&>V5XN!wO<|^N={NMedszZGc(PNZKrHU>x7A%IVvYA zzMV?B#TrvyD5*Mk<%X(To9F%dHO1~U`yzAIjoKHsh}SL<@!Z_to!l^SdHjjYxeaoc zOit=(I33t2-MX!9VbvC87nxTUe!q^+mH5CUE8+n>)NkICwLxjn_O%rxJEfs zJF4|r*p4?-*N18|#ISqcIK(wAD^v7N%*!mh*O9_2(!SnKV*YXUL|fV>hBa$aPo_qm z%_}pW@%GN6ppzEcD#TW$d|Z=dfBM$7=ZkW;O!l7bvv$VR<&F}NHce7W1VluUT@-1WMlhyK{|9RedrRQO6a<;c+#qNujqpt6|^Y&e7 zQ;F>-9<4pcKfNnw48Hg3?D>-Wk5hl%(ViNA%CGunZvOjwr_cZWWUTdNZfxyG?SwDu zz9+JPC4 zc7>mLB)0ppXJ?TD=rEdQ?wy-x- zxfLfro4lU9kY}3O|L^&yLcVoP{n`Fhr#SWW@7J5AZ)HmR+gW)g=u?c;Maz_1i+*le z6l**w|MnI0>C4V2EM7Lxy2jUfGu!#w)|=;>eo}G}FTc?JaY>AI_lrF#mz6A(HZD>3 zed!hb>(Y#KTb3EWz34XI_2NFo)DG*nnQI%Y+86buUAoeKMA$y^0=r%5l=7Vd`F^33 zbB~Bl6ZSl0xm$AU(zuQ_J7>L`tkSK#&n-PU@$Mma|BW~9OnlZacRM*lxbjA=W=44D z=PYUO=M$NQUN4&a^V01;ovF`y=Im^bbWqWJdG|wIdDanL!AjXL_kP@)&^bZ;jO_R5 zgjAo!O-4Vr{Y{*0{Y7s1*6f!v^4iad-%RzgP^P;U`c4jf_ zJ06!`{oFp|&unv7??~PyrO!{yJzKVSt4rGdIkSY9%&wVU^X{tBxyj%6EtV@Z-ISd5 zCEob9Ue*57dyOLZPkUDX^QZRu^<7MTi#|WuwVgFxY}J=3e|G8E&)X1n`gN}5kHgph z|B3Ictu1=k_-%LU%!`j|%MI(-F04P`Xy9{P@P}E*jE&U|jty%P8myh4``n5`NO`G_tn%)>uf7Nu; z4sDK>76W&|YEzjV5dzzPbaPMa=@9N&V$^f6y<{3k)RKtaYZ8&y+j~VAd$(@xz4N2| zxB7BKg{cp>m=h4~eevbQrN-e;KSPHX*qLj3Cw$A}XZZ@%?sJnS!@ z-p>*_fz31Jaj}v#5xVZj|xA|##@3Xh)$;wMh?M#*?uU~9++HI=#jVUo|W@0<1-g4D=b7E>r zCt1zy5R8B zqVO4$SXT8eDqmouBGUL_fq>LPA*+QVQ47VY7D~)oD79;$%&moTzZNP;EmE>tq!P7A zt!k0rt0`d>Eq`Y$n6i9PuWK%^X1`vS;O`Tb_bMlt@3OSanqa-k(l%;>{VWSduL;gG zyDVI1^}APDcv|&)XIc2(>hq7X2<++$US(~{r5QABseIwm=HR7IUMy{5UiMI9S)6I^ z)ol|3jxY68jjH`zbm;i9+^)rcO?$t4EW4AjOd)-_vFG9sFAYw_L zFSYWn{hzG2GHd?oTfNJ*q;e|VtRtd6om{E%u`T=6a=ovsUP-P#_k4BS=B!^Wnme z>66%3TY7DmsCcw~&c%*<$JQ5obQhAA+0K>B|5`%&_-b`eL4_~brOW+9q_f4m#V7wL z`(Rae&UNnN@U?C?y_t_?rM53vvOLL1Txw2*fbG@R+{!f!#!lP1V$Cb+XOypHEKzw? z-u3lcjYG7@6Zfd#?k1-^?+PR7$+;Id7%pGIv3=8;tcs+{N;{?aA4$<$Z&uoTtMptM zbTVrCugRO%UEDnB%BF|u>tC{472TF9@fO_ws6OVjiP!55ao+L?+=92<1thyA)xFJG zxE0!Om;8IaxlFoIn%lfTT7F`5cC>`{vt6bCr{6Y}tyZi(?K_uy#jmJ5)!n<8JJ+Us z&aFPZeYUjM^6bS^y|>PEFF5{nn_i^LyIJd#W@mglCh#$APkYdg_|t-&-C6Ui4eC0! zZf0G_xH5~2dwI(%4{L9S&DsK|Z;RSK-NI)v{z%hUGFuHNMbLPL&L2{sEV>L1JA^K06cq?oD4 zvg%WgiaSm}{`B>UpcDrYtC%Eb9N!yne*KzD*`nxu8Dr7?H*@w z-OiTRAEE%Wf%$>6@SJ-q0P=qwnn6z3B91R*wIeW(Z;^$vAV!rhfwZ|Jg_NfM*K6=oIFILQr zr}Y(&MN`chE|#esXQs%`+&fDa*V4vFP`Bow&*2s75Rl`G9Sq-o9-nb@R zag~40)!vKEF}c^v_g-2exPQ)^qMEhG7hK$VEQ{mDWJjH?9O?h|?6Oo!OWP|hs~-3w zN9u#pjlGPU%rjKwif+ukbA8>LR_2K}mwdc&L{Y!hG$Ju*YnRTIZ>uGi)*2|WUYjl0 zs{iOQ0U#9Z+J&DcvppESdwi^mG5cq zDHmR>zF_m>`03*pI5*#%zxWQX__-ge_7`2;IdR4{q1w9(lJ8aQzN=GJa?@5Yx})vg z-nI{G?LVDecV+j2ueRqhFE;O{!sJFcKXy%SHt9)ZVZR$C*VuRM#5T>~g3)k*pX}%@= zPC!&HdC%ExMt!Hu_dVRU?2$$51OCLj6}+kc_e!Ys3EXbFwM|y&iENJVKMDSOetUAd zWG_BmTK2Rv@lnveM;>+px^@}IXY5K5zmr(HBmG~J!MmQs*;8kSJuj*g10?!8)YB5Z|Rc&uR;^TRNgVsp1?@1#uSHt0qP zu3Xo%M?;`!p2VCw!K3Reck)#;{aZIt_sxV^Z+7i_bKv&ssa;16Zrx?R_2w$y+w9GU zI*z?vANuy5&x=QPf)6IdnccI?cOV@%|0uQpqs;w} za{oUn?9b%B|C*t5^?|#))cQY734OJB?I*UkpX4Jy3EF=)iT`X?|Jh>x=Qy=V8j=%a zX4W^$TsbxEq_poB=L_|YHu2Ht@1FGR-?09(&&_+$pXZ$PeV?Lu_p>4YB$>6(BI3VV z2=9q13|D>f^+wTGzx7``e80Kvm=rDlHPQa9=#>X*Y198W9WdDWMOkuYNxVzde)r=m zKR3w#XtMv&691#E{zu3BA6@c|oa;Y#drsZ_b3(YL;gZTZ6XNIA&HUMYzu;nK;+4xk z&qi)mHJi)hHhtm#@3ZAY?JB1@{QP<9X-)AAJotAZFDG0I{tET{sFVud5w!QCvH2>=G&`lW^{7Wl)cCD{_S;s<))drL1SAJ zZ@`>~G3RDVzIyiTw%y@_XL&yupJ%5zvE_LG9{C{}9|1cxN7B8{6;f|gc%ID}>ZWimE&c{AU_Cl6hK;G0%e0INmHzi+aZ%MP; zuI{q;qU2_Yx6|Hh|M>9w@ZUvNmv8-&x%YCT-rV!fJ5K+4BW2`d?7n-&)U1;dWo(7P zT_?Y-xmclk@q}IKE*q_heb-&itLb()o{M?1fUR-b`Oq~kCmT6mzTl5qDRYJI#>CD! zxhKm-6IW<(JS=yRbax0isyUD4`-1hsXD%+hnZr5P(BNIi$3Sj(&YDktho|e`jacr) zHc`%3x5)MBwx~v9*1ot#&-Am)Za4}p6#KczJ-sDKCDvt=-W4`ZZj&o)dCpHCN^Lv# z+9iGR*1W?NY-e=K{#>c>Elo5&HP>GC>(3OEuD#O~WBVrmVlkZDlfblnVsn+C%;a5h zN32y>Y>CxVs)$KUY4*)L`dMh=)FjVvo>Z2Z?3>SQn;dsEYP!COOW|7In7d`4*7Q|u z{BkMM{nj$W$mJf+0ds$AIM1%T&368;!_#LiZ&sFENZx1jJM@YB(<=w}IaXbBi2B}V z{HCMr)B*lGE25p&Us$8|`vFUD^CzVf#ZUOYoyoZ=7q7f5Dp2!6WT}^1e*c7@F#%hR zp0j^54d7jC^)-ZliBVW{rlWD^YNuTS=luezC6~&S)@fAVPK)*1djI`Bdy^SIX3pz4 zc3AAY(QO4OwO-VwFIEwGx@PX?6&>$e&TuCm75r@6tNHm#<4uLf zkrKhyi}@5MigW(?^zY;I{3#4Ealclmu335FpSMwHtFz+m6IZ|Kui}t?7rLve^F*71 z{Myq7Io~h;`uOqRzxqc@r-YupHT7aJf8XhiFU}crT>jAdFI?gBZpVdh*Z;c^B>m7z z)-hhm=Cg2vj?3>m(qEQZ_dlBH^MvV_|9Wkuueya_w!Db=vQ;Gdi*RDmZDXl-!SO4$ zz0rB}Y^qi7nh@blN{fxHs}Bff1qLTP*!wq*>6hKDAnxDXcj}e*&F$7-U?J|myX7hO zsoK7~BF+qf3)>88PJOYB3@c7iyfb0x+v%~zrB~CJ8;IHU+B}b+X%iRkZ?`d$^ zUzay@tYwOm5$;!ylDqYAVU5Znm6uJ?Q)iy8dae57x9*)F!}OI5pKPD0cs3L+=(bp* zVk{uJR5HWj)|wT8`ac%Bi#I5J=m}ZSHH9nR%USDPLYvZ_7krPV9M@62dw1^Lx#cBd ztSM~r=g#TfJ^69|@pwCV|8sY{PriTt{D)Zl#SW7_Q}0ZaU&h#YSTniP;zOj#;&3Aq z<=;=6bPQyaPv~#47j)eJereOm1h2@6+Z8gxRbq!~$HR-;%e}sdZ zqbptFhRLU;Tlf^>6caA`Gl>ZqbBWIJm|U`BqJDAQ$$!;f+15*+a_w@vYak`@QTONK zw>;I&QLB7vT3;nz5V0$87nNRcKjrKsQ330M`GMOl7S3psx$Nvyqc7N=SAC^RHl2ZA zl~a{_D~nb0wA*dj5>AsvGEQ%Qo2~3S|HadWvW07(u;t7+Dd9MCv)H1LRp}evOZn*( zD<1N{sJP?CnP)TZHTJi*yM-U)-*ewwu25@%fru-I(8EMs?cWyu=<>AZz%#jQ!H z_e@l{l$(1cxx;hLC5uig|1sm7k^aL}n-;$p&Uao}&h_|fJkjRUx!{={*0dLfW1JfE;+AehZdAH7^#xLcm!|YEx9;zD3olkYzD|u*n_eY6u z-xBKWn;r^O^|`JHQFfbge^T!nf&T&P-RGAYr*?&9PT}8najxP8i+#MaqJC}(E{Z&u zv-n!ac~+f?6E$KTio88+F1qgsSATKfnbOTlgn?j}bN%5h&&U9mCuNIlS5&!3rU;z)*LYUx>BP`L(_<5^Nrp_Ey-|MGV%t6Q zD>F6JZW_;YIh}HVeP`44S9b62_!tTpuUZyu>8Lg{vSYjD!Gn@31?0*OnC#5a&w6C? zNo0A}9hDa+ZiarWF17Xes_qcL+BqwM`(l%1;UWY6^hYf0sZ&Cwvct|wPCHR2dh^o# z@2q|*+vl{$9w=U&q&}aAiz#$>Vg8ICI-#oJyp_w8#V&L_|GoIcESG{6yo$XqO1);y z%-I>CSs(VtjY*HGqU+4j3en|32D0C*%r5;X;LLv7CHuIf_^zY%$9nFM*XP>4E7|f> z!FK~!QEyu9ghz~8WnIOgS3c&=(LA!dlKtNP>v5|BKOVlMD67J`*3Eo{c{=~`tV6bQ zwztoYR{Oq9On(2REPU zD~?xPH@oG7t8U|0#hkur(c)`+nSvk2$Zgr=YpCc{w)DrwSkHHYzklB>oL=6VRAZ1_ zYoj09B~`yJH$CII=tN!f-LtHAT|ImEkZbPA8wW0h73JDm~vN&aHemP5DBgf0xd8u@y?Uy!M)_xjc%^(nonE3bGzdDri?cVE!A&F?~Lv!X(u zR&LFI_?6*jQNqT@1{2p_TJX&K&Z{SHJkyLVlP0~l>ttoo)VG`cU@q(2@@*GN>sGF0 z{vW^pMHYkp{*4SWPg6OW+?Fidv8SM@Sy(BL{p6j;JGQ4pH~*SurFtnZTYu)VMFPvs zM6|qCd#_t~|GKJEdKA-M-*0_)_NeE}x=otbYItJr(`y%BfALv*df%=Pv5pvzoy(@D zZw&ps;9tyASE+^eUdu9Lte+Oz{*DXD_AXvsIj{0>rQ2(^^SPE`)A#>cD<^vWcji>V z=rv}u=lnm}eKbsNgUkMBd4V&nXU9IYTdqCp@xGbIj;ng6w%smK2y(ua{ldo5_x9J>A0i+a;=zh0-3oLuFlPfmS3+C=l|tn@$TZOOQUyQ4!Q01@$TK9 z?1&orPm;IB*Q0ZPd$2Pwl!`Ji2s1D+q$L)Y#205I7Nw?uy95~p1#2Us^Od)Y*6~mH zU$BSq&P4r9bC)0awCYB8G)u>I?)5?n9^8#mg(}yKRlJLIv}eD~fA3zD=5kkN_t_r@ zjh|SyKmRnByR^)0%HG!(t(Q)BJM*mXU)~R%`A?fCsDGIj?sKVn+k$Lxhpy0p8}dQDmYUrmoE$PdopLnwKriTx046E00e{ET(>%)Y+xL zD8|KpHv8cXmnnyIS2nPyO<$6|cjUmJ&a+YvWw!xi2HEjpt?e#^!LI z{QkzRZszo_Q!Zb1(R_WbNR`|0b#ncTys$k%X_h@UlS1!gvGJ=W?f>^`^ZjPSovXB1 zG7sr|XFK?9K~?0cIhKm)>B0McF_iX3NK}Y8t}YfAKh~&pLd9n5mqdQ+FP8u8l}^gv zZSZ1MEOLlv`&Z%rM)`4;?y?4#m0}0q?s;_Sp@YZI@Z7oI-`hU7V!OwF{rHS$b9{F$ zbegh9_-Uzmz>GD|RocG>&ik39;^rhb{{Uvc$ zdG6zi6_WewzdrddvnH60x76;2)q0Un_pBFWHBUT0bAt4lj`(XoBoj&;MP%Lg`n^ng zV9y`dzL!x}{`H>idI#*S>}9KVl%A2^rSiK&+2pZ?v%x)fcCSyOU#DNq?wK$x!Ai%A z!=vTcf+>Mno9aYPTz(vVVapxOl3BLvkNVgYNHSh&Sl0baDo1XL1LITG@|rcN*Iw=5 zw-Y&(zT<;skJIyGmVYWl&D$j<*k|kbE9n)c1m^u(+{}>E^YR_T5ut|NMc!v?BNtuV zu+nmMlKb>b-%hg^RY6^Uj58Bx)awl2guWzW)B(?qiZpO&~`| zGn-@X4B@o_yK+}OQ=A!>a!ShAH{QN#=JDh1krxEHH*ME4|L?h^b#v?2wQAlTK_9(} z56>}LUoL;w^5}Fyneq#BrZ3WXGj|?agmQUMvphQ|U$kj0bN;-kMV%IZCDvB?h?}3u zEf*?u{QO|vaG@%HW8{)<1h-~M>^>)G3{cYl2G>)GS}e7EcKHI_Xx`&2Kv&C9;Ab9H=M zb>c^z{=H8MUN4(IeNCB`t)*?6w!c7sm+s=S+kvJH%-sb!n^y+$XEc9M{+@c)YUzBB zHPcuA7ui=XxmnzK3%A?<=~neGZWy#C=AC|iihonE@T&hQo||X2-kkpX-4`xlb$zbB zh1qB0*PDIXeDYj(?;D>eNiFrZz2~!y8>XjMG+yvnaiOP@(>tf3#AV&3^UaKbD?}3G zPZn{e771&a+3lU_b8bSu*2bg$GwQ6;b7yDIYp{`-!}juY_mz4vwY7^@J_`HybY+$Q z?~fmOpK%15Sa7bDEa!aZ#Qf=R`r0FGQ!l6n7A)FxaMkMvc_DKa>2}TJ`L}7!1I_pM zgzm8Zd@A_Qxay&sxleM3)KY2TY|FP3dS19E-(V^H5W4Wu9n;-qQyEsSSa*C`_r|;H z!kBED%wiknz3)A{Q+L5~%lFwBHk_$Tx7ElbZ8$k^hyS*F9D8NT&(vT4 zv-0vSs~xl2oV;$aUXHvZ?RI$C=knZboxApbTUfweRnocbzq0zI(wpnbnomjc z8w}AY=h-aTN*UkZvP(5T(^%$czv$eetG~P(<)d!ROnrai(&Bm-{y+bI8>`Lvc>i79 zj(;Ea$(EQ@iC@`qN286Q;LKvjAM#Ric|YPzGF5lo=@ysZnyPf^=S7}t?>(-HpGjEj z+TO0eJtKU7{+>Oh<&tk+G2VT`?Xowc?%si1iHHXt%m!wCM%kY$jdtXpd+YCW|99K_ zUe8IhPKjUnAa3<)U(?I#cjf9=_Wl<+rlRlT(~uR00}=I~wAff6GB&ukuHEw~&?BIFBx|J-Te77yn)tOP9AR*Ir1{|E6_% z-PYX!fk*1!_gp_B;WcSq7T=A}_iFaeyle69`y+`5n^&5Ji7jn^J$v?S#Xa)<$3GnH zI&_1#DNDChp)QC^uH(f6M~lSkO7eo2-hZvmUvln>mbk$~K1F-2eE#0-iIvILYN~VJ zOYAt*b7}hNzN}@+R7_E)$ye_=Fmd(c-zs zTk;S72#Qc)J1w^6gZ64oE*~a~L*GTprYzZ1baw9z^(nW64c~q*d%17w)XBRT&Q3oR zY9riWx_tSyUHgxvc`K-nd$t(tgqhJE zh3to;BxY`IlkLrzptBZao}k5?vZYZUxFJ8S0y;k<57;YZWlo)*41WM?RL z%xN#P(B0#j|9l_F{a?3E;a2gXp616ZqIL@Lvn|V9WTabnQM2RL7GL+~)+60|S0)^2 zJ+)GIS&!bLWdRl9Uiq@@Zna|U`v2jMs~&9q zwKX$K_56!3uR0u;KC4<3+}mc4NUfk|qT;pX1#ejx80LyV26A#T^Rf{w#HZojlW$oF z?DN0+r+uDJC{s)0O_{_8lMcsyKQLEl8;@7cN$ryY)4b|_Z&R^Xxm}?!-FA)MwkOxF zuU#Mispj7ggZa!$dg_;dG`n6@cA|Lmvup10$3KKVNk93Gowt6H@?#7Cz?$_BPQQNr zn&;mlqhv3`gO1!C0To=Wi-J$MoDrI%F>9Ga#T$X-Wm{5qI|W~0U*^#1GQVR+U(`plv;uW$!?MX+%+rl&}Siug>H^`2?x+$7L4Ur|3rPh_s; zFFE;nk%y9J9oUvwo_(|SSm?3L@6ET5F5c3ix#w+5K$RTlybXH`Pv814p((3;Mru#v zv&XNJ7T&NgSzVhs>0RrQ#VN1lUJ7f57EcPCD!e2j)#X*Lp2V-i2DOzn2V`d{1+v(F zUv}Qo^wNe%>8uIIo@scqw|zQ0eXZ33`z5iZ5tSRgBe!U%7FJA~{o|(Fq6bwbZs&`Z z8VW73c(`WLz7T!4-l-q19AH`GtE5=2w4N9JvoS~KP@&a^DTh|H zRY&cdAyaL%Pt(G#ep|-rf~^~u*HlMt=lw02F)c)Vl5@w?&V+&`0R`X69dE0AEets% zId?-*`wM4VF0p3Lj=%%Y-35L%oc}nX>jL912dO&V&GNb}^$FE2RT7i8`EUv+Y`hsD zo0q|T@u1k|51YQ3RYgZO)$vSaiEAlmTgL75=7UH8qmQE4G7Z@cGHvg+oto$L`b0FScuf*wDKjGyyX$el7yff_^>m;V=7kZ-VeCwpIe476M z!IaW)smR*k`@U~AKBe$}xKe&|N3)H<&kxnls#8U5!nb&5z1^{psfzWA`F3`D?GH*# zzN^-AvnkrD+&J>>{L<|EWku14+g)#-&CmVHb|$9BOk%ys;j|s5+Vi$cy_uMvxAJY4 zany`|0`uM9{XVnDT=n0h=dV{Rxy3o_qy-Om{I;0#zo*yq{Qmp?C(HY36-mpQn{#;1 z?|3Py8$V^*vmbRUW#o@6ZU1)K`6aJRwC>+)b|vU#bNbYv^4L}pZaeGUE7{id3m0e&$Xyt zx-N+C9vk<%-z6($GkYtVJH^xNz8v#@#`$gEwf!+2n{(C}?_2+E?;7j>4PWhE+}ytW z+47At@85ANt^fIc=e5kLJHP*ZSf}Ck-eiT(>H7>{cIB|f+^RI6wODWZn~vDJht+vO zt@T@{c({GMb@%7;a;w?d&2#x;WgaQrmaJO4K>5o*X{Wo1+FLg4XJXOaCO6$GY*wwF z$EwQ5U$_pGPiI}BPztW~=sn-g zdu$<8%Rixh#TkaZWyf}YNs!-G{Be=>+?(%?K506#`2YjA#1>b}J06SLro5>z-g|%F zau2U*IZrRyE>@3?Sl)HCxXV>mMxge>EwPmMEfX(Bq(0tb@VmUyuRO@*QotG^&n@3) zy?&5Ton8H!VaDFgc5`3WWL|l*Zb7|-<>6$baLG=cMf^shlC>h-nJ?e&F0a4+`{RcX z1@qS}^_;rZD?KD*)}fjQ7rnIEr@ZnwdYUnErV5{G&^CjtAhAhZ)~P37?TAPaYWY1= zFj7(ZRPVgi9OgEMntfkyFp6EVQf1=vAPH|7nFSwXJ$L&rE92a=qNAxh+36`K|EUSzi=sYQ?KJ3#2=SX>{@!ZprVS=j zmkFH6R!dFkw~@N2cQIG%kd~6NR`-;Ni~@qo9yu;e^)l+a8lt#Kb$u_>9u1QilL9?c zo29pOVh;pAG*I)_*}ld}>cPS-=lZuURgqO@)tY^ zRnpo!A{Fl#`EN~Hc|@r2m+WmBRc(E4{WUIJ2GRxmzj z=kVg0FXl|Vxtb$0+N1FN!g)NmlU5nmD?dMF`LE?jQ~STSxAzN8@_v7>@#TlBA-v11 z+x;wlIIP-kf34X*eN}+cO1FUZfttVHe5w{zerQ;`W7jU(-hBJL`z`-l{Hw9tCwI5U zJ~lp?VPDf8fBpoXb7EO1JLCCV#8yk{9}}43;ic zC7)cugO4Xjg*zOWzF2wnKkehLmk*uZntEZAKC=AKtW5FKvmZOo z%&~GcdLzSMx;0&KP3w)eIkL~zpFO%o=v?yFOWKe8TWa6--Kbo<%`;p}R;G+KI@EXB zo{9UXYIL1(f6bi#GVjUiFMFr#l#b8MU2*@$@+&bPmaQn{j(R+G#)4Pxi+7gHUK(-x zo#v%WR!iBpPc2i-5D-c|JauOon*wKt_QjajInw;|qdsiu$d4F*(3<5!;5@v7$3CbDj|WXu|)S*VgQhlcTwjU9xp%UqIJR0i~naoAZxJ znfw$s(vxQqpUt>OG-heVs&oE|ALS(NG^c5(#q0}@JD|9K%G;FOd|S4klf*NweCFD_ zM=E|!e2v9^$^LWt>+0+5t@gjYynp-l8JqV1|M%#@M}PDA=k@LHecS6A=O<)()b00P zpBtL{Z})tgu6RxOcb3cRg-X)Lb9%TWt6yI|b1nSQ4E8I0l{wX?_S(s=z5Rvn_m>~3 z)vr%~T(+u0^ejY+;lWX%`r1~?%RFvU1j7zG)$6~ zf4wSouR`+OpAYhNFJ`I5drUKT>*lBw9QD>Hd!-MIa_?J=+5-?FCL9{ZT`E@U*A ztxqy7SMI))GB-eR$?|8{IbNntNM}l%R`#;i&E%{m6y{?9} z(I9B;)W!EQrWaY+ru=-uzgMP9aY}F8zYFiq1Va-{gMvz5j&&-Jfu-_ITZ|6pj9U1uWk3R|>zLTQBqW)5Wv<*ZfIH_sc4=dKt)W zx0jPQ)4ry54Pzj;U&i&?*24mJ)1S>cdryqOpZ#h0VKOd~|i@~iCCirw=N@}^HD)!3@>-pksSlI_k00L`W3XI9{%=FLa&FtZN9X!yKlA^5{&fHB zjOVs3#!;#H+rwX;$t|zQ;yfofL$@rud+)S<`nNnOQM$V&J#B%7{z-0>Ha6V&PF?KQo~;iT-roBA%5DMHV|p*rC!Q^cJOAtc zg~|K(c!$JR-q1PJ_$I^m%mTA`AKp((*3{X$Ud?Y?e{04nfsKdaWs}19*4$N0JUV^X zkt@3;+b`WUZOUt3*U6x|!NE^1`%Q7EyrofIea>{vTb8la{^!HeAC!kYP4|)w6qvTU zGLK_^)QY-QMju`3EfyTh>~0L1R#2N+s<-@Zv_iKJ&#tOjljA>R3Ymm=N4@!-)HcWO zPj0~7?Z>u$etvB0W;t=Ala(>QFF)Gx&g1E(KTr7A{70Hg?+x8`j~Kj-iuS+lAyVi5$X;gYs%xD0STZz46>S7AhHj0`4PCWw!-=9d zoRY6*+Xx4VJ>CC)=4@NPIRYy(cCVGy?0Y`P^8U{AHwxEp-+T2nWB1=V#fK`)PZ$|0 zxgV6=mN+AAyXD?l1wRh&U&tBfF6g^X;?4Va@5&z9o=iR^;Vb+=ljX#lLsJCBADJvk z-jkrxb->?A)o@AA^AeM%EI(R|5?;0vCxM>2%@^ zktv;ar-R$^$z_QEmRlZ{PClC7-Axw#5j&=F$UjeU_Or-S9^pIlt6xjXwx{sii+}F? z{_@TCx4H}!)1LkdeZxJ4W$p`(`X7rsWDcG_e0}|bUY&-h4>hw`?8N{;?*oJFGz3#l&FAG+(LTJ=Hl)jojHUXOzwlpYTOz zR>T$26^&}E_-`5TTFf~l=yA5c&nr-QzTiVXnZ^Hw`sW|GyC>dn>dQ}osV_{p6xAi< zC(fJECt+fDkmq>Qr+p6|rfMF&axSr_P&6^sKq=5_ve5>K2bTp7P1*3ooKNs?&&<=i znHF;VGTeW*qr+wa@4Our2RVb!$gnPwT^As;VM|+zRQ1ani|?$JPHWkm$`sYll98W( z_vDtXFP#KRAMVoEbezIAzfeR)T#VS^7=kmFHGnBul#~DWY+Psa4_!j$(cb-NlyY2+5j?aZJ=h?k^6Od_aq_z39 zWR=rN{U@g+tD0=n9hY-gWnOtDJ#A+g$Cm389Cw|{{O)~9d1LQ&hTn0A=Bmc#bTB=Q zS{Rcp@-&CBD7H!GfrI4c?(D=xjAbI5ShOOZn=Z@ei`}@MhBQu`yvWH{usWKAtp5*zT-wK}e+)YlL)F!m+mZ|K$EvzT0d6 z`@!7#ybE=w%)Y%gwfgkByvzIMt=i*y;YiTZ=!BcP{r>)4E2MtUio5WoNmb^@$Et(p zFLJ#x3%IFZTdKd|K$maeWx-i}7vAvg%lFQ!98&fN*_?oa1NT;^Ml$?j|2 zAiqeqX7yUfub!TlS!d~8C~1^m$K8>>@cuTz70cKA>NhMCH`&Xu@AYHn-SRD$E55wV z7Zl05%r~p-L&)0$yC(5OoDuve`SaxIn@s=z|2e;$Yt1sX(#)$NkJ(CB>|7}FwsSgb z-O5icpF=Bo#I9D%+9lGO`BO??_0OwYSC$4o{k6;WPrAnIxc6#H7v9^Le9$u2ux$A~ z$D2R=Ztq#nJnwwc4rkeiNB68h?zfOxSzGeDk@OSMlnr7{CXSEYHp$;NJ}R_p)=9Cm z=_{3=gtz2dlui=f^itdc|H};8VfI4m8GGZp z`X#+P%wE`@;V;eq`u}TnQdFv5pX!B0n>)UA*Up;4DYk_3@v~CJJv$ULc>VXf=&Y&U z{p^L<>92>(5?jv3t(&DX{r!@S+#8SGeYrC4Z{^XK4t4LvoekcvZxrd4Z(8Z>@Mxp@ zvaZJt^S|>SseFHRq0LL}vrE{XZkM_h&Asy4T&9Z-k4#uufB*UuG&g?b`UVGia+HaSEQU74rV_v}Ij4R((7bBKc|RQc(fXX*VNm6_4&CN0hLY=xl8lX9&-6VKN6mqx3yJHLDP&Y5LC zQ|0K&j-st?d6I8F)%kI6zu!E8quKPmyG_WBcW=FCh5yg4UGi+(rEMQpU5ZziIT=+K zTJh7N!ucWhqo=}igFZXeeEoUJd8*j#yyz7ZvvQBgKkO2jzJv3lw?9AEf_*E@XMQtW zH*slb-b$`%PnR#OD3)zQz{B2g$^y{rZ97``RRE^p~<~a)<82X-|yKn@`9|xz5Ia`{sgO`dTF`c~46Hi*jH8aDD0h zzkfoPU-=|1mSPzu_)exEy`j3{dHX`{^YN?KD;KnFe>c1M``qex^Y)jfn(p{;aQ@bb zU;b?Po%CkiFSg$-Z|f(8MNW7$J+AbwmrBfTk2_2El)bGfS?ILV?QU$~j$>J=CTiU_ zb)2iuGWQk=EbTc_F+DfNe!YP8pGR&F?E}0SnT)t`ubpLJU|?WmU|`tR2x6hGq(#C+(WWAu_SM*tWgkC-#taJ9r24I_QKp4<2%)pR_H1~k46J#~| z$S*>tsTczT>Nqg6UTlLS2)%yNScXcFwPS1XAhhpLW?(2rZvO;$v$BDt*%{awRx&a$ ISZRZJ0Kbrpg8%>k literal 0 HcmV?d00001 From d3347b6d0832eec766fb70731e9aeb07f31450b0 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 27 Jul 2000 14:27:00 +0000 Subject: [PATCH 004/133] Initial HTML commit [SVN r7640] --- index.htm | 37 ++++ scoped_array.htm | 90 ++++++++ scoped_ptr.htm | 128 +++++++++++ shared_array.htm | 180 ++++++++++++++++ shared_ptr.htm | 206 ++++++++++++++++++ smart_ptr.htm | 138 ++++++++++++ smarttests.htm | 540 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1319 insertions(+) create mode 100644 index.htm create mode 100644 scoped_array.htm create mode 100644 scoped_ptr.htm create mode 100644 shared_array.htm create mode 100644 shared_ptr.htm create mode 100644 smart_ptr.htm create mode 100644 smarttests.htm diff --git a/index.htm b/index.htm new file mode 100644 index 0000000..04643fa --- /dev/null +++ b/index.htm @@ -0,0 +1,37 @@ + + + + +Boost Smart Pointer Library + + + + + + + + + + + + + + +
c++boost.gif (8819 bytes)Home Libraries People FAQ More
+ +

Smart pointer library

+ +

The header smart_ptr.h provides four smart pointer classes.  Smart pointers ease +the management of memory dynamically allocated with C++ new expressions. + +

+ +

Revised July 23, 1999

+ + diff --git a/scoped_array.htm b/scoped_array.htm new file mode 100644 index 0000000..3bf65cd --- /dev/null +++ b/scoped_array.htm @@ -0,0 +1,90 @@ + + + +scoped_array + + + + + + +

c++boost.gif (8819 bytes)Class +scoped_array

+

Class scoped_array 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 scoped_array::reset().

+

Class scoped_array is a simple solution for simple +needs.  It cannot be used in C++ Standard Library containers.  See shared_array +if scoped_array does not meet your needs.

+

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

+

Because scoped_array is so simple, in its usual +implementation every operation is as fast as a built-in array pointer and has no +more space overhead that a built-in array pointer.

+

A heavier duty alternative to a scoped_array is a scoped_ptr +to a C++ Standard Library vector.

+

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

+

Class scoped_array Synopsis

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

Class scoped_array Members

+

scoped_array element_type

+
typedef T element_type;
+

Provides the type of the stored pointer.

+

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

+

scoped_array destructor

+
~scoped_array();
+

Deletes the array pointed to by the stored pointer.  Note that in C++ delete[] +on a pointer with a value of 0 is harmless.

+

Does not throw exceptions.

+

scoped_array reset

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

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.

+

Does not throw exceptions.

+

scoped_array operator[]

+

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 get()==0, +or if i is less than 0 or is greater or equal to the number of elements +in the array.

+

scoped_array get

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

Returns the stored pointer.

+

Class scoped_array example

+

[To be supplied. In the meantime, see smart_ptr_test.cpp.]

+
+

Revised  December 8, 1999

+

İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, +modify, sell and distribute this document is granted provided this copyright +notice appears in all copies. This document is provided "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..3430481 --- /dev/null +++ b/scoped_ptr.htm @@ -0,0 +1,128 @@ + + + +scoped_ptr + + + + + + +

c++boost.gif (8819 bytes)Class +scoped_ptr

+

Class scoped_ptr 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 scoped_ptr::reset().  +See example.

+

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

+

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

+

Because scoped_ptr is so simple, in its usual implementation +every operation is as fast as a built-in pointer and has no more space overhead +that a built-in pointer.

+

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

+

Class scoped_ptr Synopsis

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

Class scoped_ptr Members

+

scoped_ptr element_type

+
typedef T element_type;
+

Provides the type of the stored pointer.

+

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

+

scoped_ptr destructor

+
~scoped_ptr();
+

Deletes the object pointed to by the stored pointer.  Note that in C++, delete +on a pointer with a value of 0 is harmless.

+

Does not throw exceptions.

+

scoped_ptr reset

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

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.

+

Does not throw exceptions.

+

scoped_ptr operator*

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

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

+

scoped_ptr operator-> and get

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

Both return the stored pointer.

+

Class scoped_ptr examples

+
#include <iostream>
+#include <boost/smart_ptr.h>
+
+struct Shoe { ~Shoe(){ std::cout << "Buckle my shoe" << std::endl; } };
+
+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() << std::endl;
+    std::cout << my_instance.add_one() << std::endl;
+    }
+

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

+
+
1
+2
+Buckle my shoe
+
+

Handle/Body Idiom

+

One common usage of shared_pointer is to implement a handle/body +structure which avoids exposing the body (implementation) in the header file:

+
class handle
+{
+public:    // simple forwarding functions to the body class
+    void f();
+    void g(int);
+private:
+    friend class body;  //incomplete class hides implementation
+    boost::scoped_ptr<body> imp;
+};
+

This code requires that class body have a trivial destructor to +avoid undefined behavior.  This is because the definition of class +body is not visible at the time scoped_ptr<> deletes it. See ISO +5.3.5/5.  Note that some compilers will issue a warning even though the +above code is well defined.

+
+

Revised 24 July 2000

+

İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, +modify, sell and distribute this document is granted provided this copyright +notice appears in all copies. This document is provided "as is" +without express or implied warranty, and with no claim as to its suitability for +any purpose.

+ + + + diff --git a/shared_array.htm b/shared_array.htm new file mode 100644 index 0000000..eebafdc --- /dev/null +++ b/shared_array.htm @@ -0,0 +1,180 @@ + + + +shared_array + + + + + + +

c++boost.gif (8819 bytes)Class +shared_array

+

Class shared_array 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 shared_array, on shared_array::operator=(), +or via an explicit shared_array::reset().  See example.

+

Class shared_array meets the CopyConstuctible +and Assignable requirements of the C++ Standard Library, and so +can be used in C++ Standard Library containers.  A specialization of std:: +less< > for  boost::shared_ptr<Y> is supplied so that  +shared_array works by default for Standard Library's Associative +Container Compare template parameter.  For compilers not supporting partial +specialization, the user must explicitly pass the less<> functor.

+

Class shared_array cannot correctly hold a pointer to a +single object.  See shared_array +for that usage.

+

Class shared_array will not work correctly with cyclic data +structures. For example, if main() holds a shared_array pointing to array A, +which directly or indirectly holds a shared_array pointing back to array A, then +array A's use_count() will be 2, and destruction of the main() shared_array will +leave array A dangling with a use_count() of 1.

+

A heavier duty alternative to a shared_array is a shared_ptr +to a C++ Standard Library vector.

+

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

+

Class shared_array Synopsis

+
#include <boost/smart_ptr.hpp>
+namespace boost {
+
+template<typename T> class shared_array {
+
+ public:
+   typedef T element_type;
+
+   explicit shared_array( T* p=0 );
+   shared_array( const shared_array& );  // never throws   
+   ~shared_array();
+
+   shared_array& operator=( const shared_array& );  // never throws  
+
+   void reset( T* p=0 );
+
+   T& operator[](std::size_t i) const;  // never throws
+   T* get() const;  // never throws
+
+   long use_count() const;  // never throws
+   bool unique() const;  // never throws
+
+   void swap( shared_array<T>& other ) throw()
+   };
+
+template<typename T>
+  inline bool operator==(const shared_array<T>& a, const shared_array<T>& b)
+    { return a.get() == b.get(); }
+
+template<typename T>
+  inline bool operator!=(const shared_array<T>& a, const shared_array<T>& b)
+    { return a.get() != b.get(); }
+}
+
namespace std {
+
+template<typename T>
+  inline void swap(boost::shared_array<T>& a, boost::shared_array<T>& b)
+    { a.swap(b); }
+
+template<typename T>
+  struct less< boost::shared_array<T> >
+    : binary_function<boost::shared_array<T>, boost::shared_array<T>, bool>
+  {
+    bool operator()(const boost::shared_array<T>& a,
+        const boost::shared_array<T>& b) const
+      { return less<T*>()(a.get(),b.get()); }
+  };
+
+} // namespace std 
+

Specialization of std::swap uses the fast, non-throwing swap that's provided +as a member function instead of using the default algorithm which creates a +temporary and uses assignment.
+
+Specialization of std::less allows use of shared arrays as keys in C++ +Standard Library associative collections.
+
+The std::less specializations use std::less<T*> to perform the +comparison.  This insures that pointers are handled correctly, since the +standard mandates that relational operations on pointers are unspecified (5.9 [expr.rel] +paragraph 2) but std::less<> on pointers is well-defined (20.3.3 [lib.comparisons] +paragraph 8).
+
+It's still a controversial question whether supplying only std::less is better +than supplying a full range of comparison operators (<, >, <=, >=).

+

The current implementation does not supply the specializations if the macro +name BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION is defined.

+

Class shared_array Members

+

shared_array element_type

+
typedef T element_type;
+

Provides the type of the stored pointer.

+

shared_array constructors

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

Constructs a shared_array, storing a copy of p, +which must have been allocated via a C++ new[] expression or be 0. +Afterwards, use_count() is 1 (even if p==0; see ~shared_array).

+

The only exception which may be thrown is std::bad_alloc.  If +an exception is thrown,  delete[] p is called.

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

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

+

shared_array destructor

+
~shared_array();
+

If use_count() == 1, deletes the array pointed to by the +stored pointer. Otherwise, use_count() for any remaining +copies is decremented by 1. Note that in C++ delete[] on a pointer with +a value of 0 is harmless.

+

Does not throw exceptions.

+

shared_array operator=

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

First, if use_count() == 1, deletes the array pointed to by +the stored pointer. Otherwise, use_count() for any +remaining copies is decremented by 1. Note that in C++ delete[] on a +pointer with a value of 0 is harmless.

+

Then replaces the contents of this, as if by storing a copy +of the pointer stored in r. Afterwards, use_count() +for all copies is 1 more than the initial r.use_count()

+

shared_array reset

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

First, if use_count() == 1, deletes the array pointed to by +the stored pointer. Otherwise, use_count() for any +remaining copies is decremented by 1. Note that in C++  delete[] +on a pointer with a value of 0 is harmless.

+

Then replaces the contents of this, as if by storing a copy +of p, which must have been allocated via a C++ new[] +expression or be 0. Afterwards, use_count() is 1 (even if p==0; +see ~shared_array).

+

The only exception which may be thrown is std::bad_alloc.  If +an exception is thrown,  delete[] p is called.

+

shared_array operator[]

+

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 get()==0, +or if i is less than 0 or is greater or equal to the number of elements +in the array.

+

shared_array get

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

Returns the stored pointer.

+

shared_array use_count

+

long use_count() const; // never throws

+

Returns the number of shared_arrays sharing ownership of the +stored pointer.

+

shared_array unique

+

bool unique() const; // never throws

+

Returns use_count() == 1.

+

shared_array swap

+

void swap( shared_array<T>& other ) throw()

+

Swaps the two smart pointers, as if by std::swap.

+

Class shared_array example

+

[To be supplied. In the meantime, see smart_ptr_test.cpp.]

+
+

Revised December 8, 1999

+

İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, +modify, sell and distribute this document is granted provided this copyright +notice appears in all copies. This document is provided "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..3fdca13 --- /dev/null +++ b/shared_ptr.htm @@ -0,0 +1,206 @@ + + + +shared_ptr + + + + + + +

c++boost.gif (8819 bytes)Class +shared_ptr

+

Class shared_ptr 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 deleted or reset.  +See example.

+

Class shared_ptr meets the CopyConstuctible +and Assignable requirements of the C++ Standard Library, and so +can be used in C++ Standard Library containers.  A specialization of std:: +less< > for  boost::shared_ptr<Y> is supplied so that  +shared_ptr works by default for Standard Library's Associative +Container Compare template parameter.  For compilers not supporting partial +specialization, the user must explicitly pass the less<> functor.

+

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

+

Class shared_ptr will not work correctly with cyclic data +structures. For example, if main() holds a shared_ptr to object A, which +directly or indirectly holds a shared_ptr back to object A, then object A's +use_count() will be 2, and destruction of the main() shared_ptr will leave +object A dangling with a use_count() of 1.

+

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

+

Class shared_ptr Synopsis

+
#include <boost/smart_ptr.hpp>
+namespace boost {
+
+template<typename T> class shared_ptr {
+
+ public:
+   typedef T element_type;
+
+   explicit shared_ptr( T* p=0 );
+   ~shared_ptr();
+
+   shared_ptr( const shared_ptr& );   
+   template<typename Y>
+      shared_ptr(const shared_ptr<Y>& r);  // never throws
+   template<typename Y>
+      shared_ptr(std::auto_ptr<Y>& r);
+
+   shared_ptr& operator=( const shared_ptr& );  // never throws  
+   template<typename Y>
+      shared_ptr& operator=(const shared_ptr<Y>& r);  // never throws
+   template<typename Y>
+      shared_ptr& operator=(std::auto_ptr<Y>& r);
+
+   void reset( T* p=0 );
+
+   T& operator*() const;  // never throws
+   T* operator->() const;  // never throws
+   T* get() const;  // never throws
+
+   long use_count() const;  // never throws
+   bool unique() const;  // never throws
+
+   void swap( shared_ptr<T>& other ) throw()
+   };
+
+template<typename T, typename U>
+  inline bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b)
+    { return a.get() == b.get(); }
+
+template<typename T, typename U>
+  inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b)
+    { return a.get() != b.get(); }
+}
+
namespace std {
+
+template<typename T>
+  inline void swap(boost::shared_ptr<T>& a, boost::shared_ptr<T>& b)
+    { a.swap(b); }
+
+template<typename T>
+  struct less< boost::shared_ptr<T> >
+    : binary_function<boost::shared_ptr<T>, boost::shared_ptr<T>, bool>
+  {
+    bool operator()(const boost::shared_ptr<T>& a,
+        const boost::shared_ptr<T>& b) const
+      { return less<T*>()(a.get(),b.get()); }
+  };
+
+} // namespace std 
+

Specialization of std::swap uses the fast, non-throwing swap that's provided +as a member function instead of using the default algorithm which creates a +temporary and uses assignment.
+
+Specialization of std::less allows use of shared pointers as keys in C++ +Standard Library associative collections.
+
+The std::less specializations use std::less<T*> to perform the +comparison.  This insures that pointers are handled correctly, since the +standard mandates that relational operations on pointers are unspecified (5.9 [expr.rel] +paragraph 2) but std::less<> on pointers is well-defined (20.3.3 [lib.comparisons] +paragraph 8).
+
+It's still a controversial question whether supplying only std::less is better +than supplying a full range of comparison operators (<, >, <=, >=).

+

The current implementation does not supply the specializations if the macro +name BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION is defined.

+

The current implementation does not supply the member template functions if +the macro name BOOST_NO_MEMBER_TEMPLATES is defined.

+

Class shared_ptr Members

+

shared_ptr element_type

+
typedef T element_type;
+

Provides the type of the stored pointer.

+

shared_ptr constructors

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

Constructs a shared_ptr, storing a copy of p, which +must have been allocated via a C++ new expression or be 0. Afterwards, use_count() +is 1 (even if p==0; see ~shared_ptr).

+

The only exception which may be thrown by this constructor is std::bad_alloc.   +If an exception is thrown,  delete p is called.

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

Constructs a shared_ptr, as if by storing a copy of the +pointer stored in r. Afterwards, use_count() +for all copies is 1 more than the initial r.use_count(), or 1 +in the auto_ptr case. In the auto_ptr case, r.release() +is called.

+

The only exception which may be thrown by the constructor from auto_ptr +is std::bad_alloc.   If an exception is thrown, that +constructor has no effect.

+

shared_ptr destructor

+
~shared_ptr();
+

If use_count() == 1, deletes the object pointed to by the +stored pointer. Otherwise, use_count() for any remaining +copies is decremented by 1. Note that in C++  delete on a pointer +with a value of 0 is harmless.

+

Does not throw exceptions.

+

shared_ptr operator=

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

First, if use_count() == 1, deletes the object pointed to by +the stored pointer. Otherwise, use_count() for any +remaining copies is decremented by 1. Note that in C++  delete on +a pointer with a value of 0 is harmless.

+

Then replaces the contents of this, as if by storing a copy +of the pointer stored in r. Afterwards, use_count() +for all copies is 1 more than the initial r.use_count(), or 1 +in the auto_ptr case. In the auto_ptr case, r.release() +is called.

+

The first two forms of operator= above do not throw exceptions.

+

The only exception which may be thrown by the auto_ptr form +is std::bad_alloc.   If an exception is thrown, the function +has no effect.

+

shared_ptr reset

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

First, if use_count() == 1, deletes the object pointed to by +the stored pointer. Otherwise, use_count() for any +remaining copies is decremented by 1. 

+

Then replaces the contents of this, as if by storing a copy +of p, which must have been allocated via a C++ new +expression or be 0. Afterwards, use_count() is 1 (even if p==0; +see ~shared_ptr). Note that in C++  delete +on a pointer with a value of 0 is harmless.

+

The only exception which may be thrown is std::bad_alloc.  If +an exception is thrown,  delete p is called.

+

shared_ptr operator*

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

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

+

shared_ptr operator-> and get

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

Both return the stored pointer.

+

shared_ptr use_count

+

long use_count() const; // never throws

+

Returns the number of shared_ptrs sharing ownership of the +stored pointer.

+

shared_ptr unique

+

bool unique() const; // never throws

+

Returns use_count() == 1.

+

shared_ptr swap

+

void swap( shared_ptr<T>& other ) throw()

+

Swaps the two smart pointers, as if by std::swap.

+

Class shared_ptr example

+

[To be supplied. In the meantime, see smart_ptr_test.cpp.]

+
+

Revised December 8, 1999

+

İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, +modify, sell and distribute this document is granted provided this copyright +notice appears in all copies. This document is provided "as is" +without express or implied warranty, and with no claim as to its suitability for +any purpose.

+ + + + diff --git a/smart_ptr.htm b/smart_ptr.htm new file mode 100644 index 0000000..ab95fc8 --- /dev/null +++ b/smart_ptr.htm @@ -0,0 +1,138 @@ + + + + + + +Smart Pointer Classes + + + + +

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

+

Smart pointers are classes 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 header boost/smart_ptr.hpp +provides four smart pointer template classes:

+
+ + + + + + + + + + + + + + + + + +
+

scoped_ptr

Simple sole ownership of single objects.
scoped_arraySimple sole ownership of arrays.
shared_ptrObject ownership shared among multiple pointers
shared_arrayArray ownership shared among multiple pointers.
+
+

These classes are designed to complement the C++ Standard Library auto_ptr +class.

+

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 Smart Pointer Timings will be of +interest to those curious about performance issues.

+

Common requirements

+

These smart pointer classes have a template parameter, T, which +specifies the type of the object pointed to by the smart pointer.  The +behavior of all four classes is undefined if the destructor or operator delete +for objects of type T throws exceptions.

+

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 four classes 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

+

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.  See the +revision history in smart_ptr.hpp +for the specific changes made as a result of their constructive criticism.

+

Oct, 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.

+

See the Revision History section of the header for further contributors.

+
+

Revised  24 Jul 2000

+

İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, +modify, sell and distribute this document is granted provided this copyright +notice appears in all copies. This document is provided "as is" +without express or implied warranty, and with no claim as to its suitability for +any purpose.

+ + + + diff --git a/smarttests.htm b/smarttests.htm new file mode 100644 index 0000000..dd976e4 --- /dev/null +++ b/smarttests.htm @@ -0,0 +1,540 @@ + + +boost: smart pointer tests + + + + +

c++boost.gif (8819 bytes)Smart +Pointers 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.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
   
   
   
  
   
+

 

+

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 21 Feb 2000 +

+

İ 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.

+ + From 00c5642eb46d5d2bb06fdd0596b5b5ddb20d5f2b Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 3 Aug 2000 15:26:16 +0000 Subject: [PATCH 005/133] 1.17.0 release candidate runup [SVN r7683] --- index.htm | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/index.htm b/index.htm index 04643fa..4a15b3e 100644 --- a/index.htm +++ b/index.htm @@ -4,34 +4,36 @@ Boost Smart Pointer Library + - - - - - - + + + + + +
c++boost.gif (8819 bytes)Home Libraries People FAQ More c++boost.gif (8819 bytes)HomeLibrariesPeopleFAQMore
-

Smart pointer library

- -

The header smart_ptr.h provides four smart pointer classes.  Smart pointers ease -the management of memory dynamically allocated with C++ new expressions. - +

The header smart_ptr.hpp provides four smart pointer classes.  Smart +pointers ease the management of memory dynamically allocated with C++ new +expressions.

+

Revised 02 Aug 2000 +

-

Revised July 23, 1999

+ From 1412e40490deb3feb9c8603e0a64d466e2309f6f Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 19 Oct 2000 21:16:46 +0000 Subject: [PATCH 006/133] Make shared_ptr ctor from auto_ptr explicit. (Robert Vugts) [SVN r8012] --- include/boost/smart_ptr.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp index 353e472..686df8d 100644 --- a/include/boost/smart_ptr.hpp +++ b/include/boost/smart_ptr.hpp @@ -9,6 +9,7 @@ // See http://www.boost.org for most recent version including documentation. // Revision History +// 19 Oct 00 Make shared_ptr ctor from auto_ptr explicit. (Robert Vugts) // 24 Jul 00 Change throw() to // never throws. See lib guidelines // Exception-specification rationale. (Beman Dawes) // 22 Jun 00 Remove #if continuations to fix GCC 2.95.2 problem (Beman Dawes) @@ -140,7 +141,7 @@ template class shared_ptr { } template - shared_ptr(std::auto_ptr& r) { + explicit shared_ptr(std::auto_ptr& r) { pn = new long(1); // may throw px = r.release(); // fix: moved here to stop leak if new throws } @@ -164,7 +165,7 @@ template class shared_ptr { return *this; } #else - shared_ptr(std::auto_ptr& r) { + explicit shared_ptr(std::auto_ptr& r) { pn = new long(1); // may throw px = r.release(); // fix: moved here to stop leak if new throws } From db43d160b4a58d1295f95d38e72f2ddf7462ab5c Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 10 Nov 2000 15:39:05 +0000 Subject: [PATCH 007/133] libraries.htm and people.htm moved to sub-directories to make root directory cleaner. [SVN r8166] --- index.htm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.htm b/index.htm index 4a15b3e..da4e16f 100644 --- a/index.htm +++ b/index.htm @@ -13,8 +13,8 @@ c++boost.gif (8819 bytes) Home - Libraries - People + Libraries + People FAQ More @@ -31,7 +31,7 @@ expressions.
  • Submitted by Greg Colvin and Beman Dawes.
  • -

    Revised 02 Aug 2000 +

    Revised 10 Nov 2000

    From 4e832788bfae6fdbfc1aac88c37b6dd47103c2ea Mon Sep 17 00:00:00 2001 From: John Maddock Date: Thu, 16 Nov 2000 11:17:22 +0000 Subject: [PATCH 008/133] Fix for egcs 1.1.1 problems with std::auto_ptr [SVN r8225] --- include/boost/smart_ptr.hpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp index 686df8d..59e42a7 100644 --- a/include/boost/smart_ptr.hpp +++ b/include/boost/smart_ptr.hpp @@ -139,12 +139,13 @@ template class shared_ptr { shared_ptr(const shared_ptr& r) : px(r.px) { // never throws ++*(pn = r.pn); } - +#ifndef BOOST_NO_AUTO_PTR template explicit shared_ptr(std::auto_ptr& r) { pn = new long(1); // may throw px = r.release(); // fix: moved here to stop leak if new throws - } + } +#endif template shared_ptr& operator=(const shared_ptr& r) { @@ -152,6 +153,7 @@ template class shared_ptr { return *this; } +#ifndef BOOST_NO_AUTO_PTR template shared_ptr& operator=(std::auto_ptr& r) { // code choice driven by guarantee of "no effect if new throws" @@ -164,7 +166,9 @@ template class shared_ptr { px = r.release(); // fix: moved here so doesn't leak if new throws return *this; } +#endif #else +#ifndef BOOST_NO_AUTO_PTR explicit shared_ptr(std::auto_ptr& r) { pn = new long(1); // may throw px = r.release(); // fix: moved here to stop leak if new throws @@ -181,6 +185,7 @@ template class shared_ptr { px = r.release(); // fix: moved here so doesn't leak if new throws return *this; } +#endif #endif void reset(T* p=0) { @@ -371,3 +376,4 @@ template #endif // BOOST_SMART_PTR_HPP + From 26fe4c40788dd94f5bf09da8b64748a6c9fe3fdc Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Wed, 6 Dec 2000 14:46:44 +0000 Subject: [PATCH 009/133] Fix typo shared_array should have read shared_ptr in one place (Ed Brey) [SVN r8392] --- shared_array.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared_array.htm b/shared_array.htm index eebafdc..89d9339 100644 --- a/shared_array.htm +++ b/shared_array.htm @@ -23,7 +23,7 @@ shared_array works by default for Standard Library's Associative Container Compare template parameter.  For compilers not supporting partial specialization, the user must explicitly pass the less<> functor.

    Class shared_array cannot correctly hold a pointer to a -single object.  See shared_array +single object.  See shared_ptr for that usage.

    Class shared_array will not work correctly with cyclic data structures. For example, if main() holds a shared_array pointing to array A, From cb1b1b7cc09032c588e1842be3e7f813d1a9f2f0 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 22 Jan 2001 04:53:38 +0000 Subject: [PATCH 010/133] Suppress some useless warnings with MSVC [SVN r8704] --- include/boost/smart_ptr.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp index 59e42a7..162b458 100644 --- a/include/boost/smart_ptr.hpp +++ b/include/boost/smart_ptr.hpp @@ -9,6 +9,7 @@ // See http://www.boost.org for most recent version including documentation. // Revision History +// 21 Jan 01 Suppress some useless warnings with MSVC (David Abrahams) // 19 Oct 00 Make shared_ptr ctor from auto_ptr explicit. (Robert Vugts) // 24 Jul 00 Change throw() to // never throws. See lib guidelines // Exception-specification rationale. (Beman Dawes) @@ -75,7 +76,14 @@ template class scoped_ptr : noncopyable { void reset( T* p=0 ) { if ( ptr != p ) { delete ptr; ptr = p; } } T& operator*() const { return *ptr; } // never throws +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation +#endif T* operator->() const { return ptr; } // never throws +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif T* get() const { return ptr; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! @@ -204,7 +212,14 @@ template class shared_ptr { } // reset T& operator*() const { return *px; } // never throws +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation +#endif T* operator->() const { return px; } // never throws +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif T* get() const { return px; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! From 16902b1f4ffb71eb3249a3fe8181e89c79ef18cc Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 9 Feb 2001 14:39:43 +0000 Subject: [PATCH 011/133] Add example [SVN r9054] --- shared_ptr.htm | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index 3fdca13..0d489ad 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -192,7 +192,31 @@ stored pointer.

    void swap( shared_ptr<T>& other ) throw()

    Swaps the two smart pointers, as if by std::swap.

    Class shared_ptr example

    -

    [To be supplied. In the meantime, see smart_ptr_test.cpp.]

    +
    //  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).
    +
    +class Foo { ... };
    +
    +typedef boost::shared_ptr<Foo> FooPtr;
    +
    +std::vector<FooPtr> foo_vector;
    +std::set<FooPtr>    foo_set; // NOT multiset!
    +
    +...
    +{ // creation loop
    +  FooPtr foo_ptr ( new Foo( ... ) );
    +  foo_vector.push_back( foo_ptr );
    +  foo_set.insert( foo_ptr );
    +}
    +

    Note that at the termination of the creation loop, some of the FooPtr objects +may have use_count()==1 rather than use_count()==2, since foo_set is a std::set +rather than a std::multiset.  Furthermore, use_count() will be even higher +at various times inside the loop, as container operations are performed.  +More complicated yet, the container operations may throw exceptions under a +variety of circumstances.  Without using a smart pointer, memory and +exception management would be a nightmare.


    Revised December 8, 1999

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, From e57d3f4bc1e77ea51289141f7bccfb2df97cd835 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Sat, 10 Feb 2001 12:47:02 +0000 Subject: [PATCH 012/133] Fix revision date [SVN r9069] --- shared_ptr.htm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index 0d489ad..b478dc9 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -218,7 +218,8 @@ More complicated yet, the container operations may throw exceptions under a variety of circumstances.  Without using a smart pointer, memory and exception management would be a nightmare.


    -

    Revised December 8, 1999

    +

    Revised 09 February, 2001 +

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" From 6a12efb77bf64e79c232b37057129a603356b327 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Wed, 14 Mar 2001 15:11:55 +0000 Subject: [PATCH 013/133] 1.21.1 run up, including new download instructions and fix broken hyperlinks [SVN r9557] --- index.htm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/index.htm b/index.htm index da4e16f..9c8e78a 100644 --- a/index.htm +++ b/index.htm @@ -27,11 +27,10 @@ expressions.

  • Documentation (HTML).
  • Header smart_ptr.hpp
  • Test program smart_ptr_test.cpp.
  • -
  • Download all of Boost (ZIP format).
  • Submitted by Greg Colvin and Beman Dawes.
  • -

    Revised 10 Nov 2000 +

    Revised 14 Mar 2001

    From 060ea4a573e1b8841148e3d9cd441a7ccfd2e8ca Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Sun, 18 Mar 2001 22:25:51 +0000 Subject: [PATCH 014/133] Add a couple of comments to cut down on FAQ's [SVN r9581] --- include/boost/smart_ptr.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp index 162b458..e549f91 100644 --- a/include/boost/smart_ptr.hpp +++ b/include/boost/smart_ptr.hpp @@ -250,7 +250,7 @@ template class shared_ptr { void dispose() { if (--*pn == 0) { delete px; delete pn; } } void share(T* rpx, long* rpn) { - if (pn != rpn) { + if (pn != rpn) { // assert ((pn==rpn) == (px==rpx)) dispose(); px = rpx; ++*(pn = rpn); @@ -287,7 +287,7 @@ template class shared_array { ~shared_array() { dispose(); } shared_array& operator=(const shared_array& r) { - if (pn != r.pn) { + if (pn != r.pn) { //assert ((pn==r.pn) == (px==r.px)) dispose(); px = r.px; ++*(pn = r.pn); From 2d342f0ddfbe852290b666b812f3acecabd87837 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Mon, 19 Mar 2001 12:34:12 +0000 Subject: [PATCH 015/133] Comment corrected (thanks to Joe Gottman) [SVN r9582] --- include/boost/smart_ptr.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp index e549f91..1decce7 100644 --- a/include/boost/smart_ptr.hpp +++ b/include/boost/smart_ptr.hpp @@ -250,7 +250,7 @@ template class shared_ptr { void dispose() { if (--*pn == 0) { delete px; delete pn; } } void share(T* rpx, long* rpn) { - if (pn != rpn) { // assert ((pn==rpn) == (px==rpx)) + if (pn != rpn) { // Q: why not px != rpx? A: fails when both == 0 dispose(); px = rpx; ++*(pn = rpn); @@ -287,7 +287,7 @@ template class shared_array { ~shared_array() { dispose(); } shared_array& operator=(const shared_array& r) { - if (pn != r.pn) { //assert ((pn==r.pn) == (px==r.px)) + if (pn != r.pn) { // Q: why not px != r.px? A: fails when both px == 0 dispose(); px = r.px; ++*(pn = r.pn); From 55a377b44668366ba02612929f7f3dd743748e7b Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Wed, 25 Apr 2001 00:24:50 +0000 Subject: [PATCH 016/133] Change all eGroups references to YahooGroups [SVN r9979] --- scoped_ptr.htm | 2 +- shared_ptr.htm | 2 +- smart_ptr.htm | 2 +- smarttests.htm | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scoped_ptr.htm b/scoped_ptr.htm index 3430481..0e47606 100644 --- a/scoped_ptr.htm +++ b/scoped_ptr.htm @@ -116,7 +116,7 @@ body is not visible at the time scoped_ptr<> deletes it. See ISO 5.3.5/5.  Note that some compilers will issue a warning even though the above code is well defined.


    -

    Revised 24 July 2000

    +

    Revised 27 July 2000

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" diff --git a/shared_ptr.htm b/shared_ptr.htm index b478dc9..affff12 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -218,7 +218,7 @@ More complicated yet, the container operations may throw exceptions under a variety of circumstances.  Without using a smart pointer, memory and exception management would be a nightmare.


    -

    Revised 09 February, 2001 +

    Revised 10 February, 2001

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright diff --git a/smart_ptr.htm b/smart_ptr.htm index ab95fc8..dc5db1f 100644 --- a/smart_ptr.htm +++ b/smart_ptr.htm @@ -125,7 +125,7 @@ implementation.

    See the Revision History section of the header for further contributors.


    Revised  24 Jul 200027 Jul 2000

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright diff --git a/smarttests.htm b/smarttests.htm index dd976e4..f78b618 100644 --- a/smarttests.htm +++ b/smarttests.htm @@ -530,7 +530,7 @@ Pointers Timings spreads its information as in the case of linked pointer.


    -

    Revised 21 Feb 2000 +

    Revised 27 Jul 2000

    İ Copyright Gavin Collings 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all From 3b183163c9ab8b5995cd7c3e832b0c79b57dfca9 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 10 May 2001 16:00:49 +0000 Subject: [PATCH 017/133] Clarify rationale for noncopyability [SVN r10085] --- scoped_array.htm | 17 +++++++++++------ scoped_ptr.htm | 17 ++++++++++++----- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/scoped_array.htm b/scoped_array.htm index 3bf65cd..e317e21 100644 --- a/scoped_array.htm +++ b/scoped_array.htm @@ -15,16 +15,21 @@ allocated array. (Dynamically allocated arrays are allocated with the C++ ne expression.)   The array pointed to is guaranteed to be deleted, either on destruction of the scoped_array, or via an explicit scoped_array::reset().

    Class scoped_array is a simple solution for simple -needs.  It cannot be used in C++ Standard Library containers.  See shared_array +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.  By +being 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.

    Class scoped_array cannot correctly hold a pointer to a single object.  See scoped_ptr for that usage.

    -

    Because scoped_array is so simple, in its usual -implementation every operation is as fast as a built-in array pointer and has no -more space overhead that a built-in array pointer.

    -

    A heavier duty alternative to a scoped_array is a scoped_ptr -to a C++ Standard Library vector.

    +

    A C++ Standard Library vector is a heavier duty alternative to a scoped_array.

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

    diff --git a/scoped_ptr.htm b/scoped_ptr.htm index 0e47606..27512d1 100644 --- a/scoped_ptr.htm +++ b/scoped_ptr.htm @@ -16,14 +16,21 @@ expression.)   The object pointed to is guaranteed to be deleted, either on destruction of the scoped_ptr, or via an explicit scoped_ptr::reset().  See example.

    Class scoped_ptr is a simple solution for simple -needs.  It cannot be used in C++ Standard Library containers.  See shared_ptr +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.  By +being noncopyable, it is +safer than shared_ptr or std::auto_ptr for pointers which should not be +copied.

    +

    Because scoped_ptr is so simple, in its usual implementation +every operation is as fast as for a built-in pointer and it has no more space overhead +that a built-in pointer.

    +

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

    Class scoped_ptr cannot correctly hold a pointer to a dynamically allocated array.  See scoped_array for that usage.

    -

    Because scoped_ptr is so simple, in its usual implementation -every operation is as fast as a built-in pointer and has no more space overhead -that a built-in pointer.

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

    @@ -116,7 +123,7 @@ body is not visible at the time scoped_ptr<> deletes it. See ISO 5.3.5/5.  Note that some compilers will issue a warning even though the above code is well defined.


    -

    Revised 27 July 2000

    +

    Revised 10 May 2001

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" From 8f23f07740e3e76ff71b83d1f14fe9727ed0849c Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Mon, 21 May 2001 14:56:51 +0000 Subject: [PATCH 018/133] Fix transitive dependency bug [SVN r10164] --- include/boost/smart_ptr.hpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp index 1decce7..2111032 100644 --- a/include/boost/smart_ptr.hpp +++ b/include/boost/smart_ptr.hpp @@ -9,6 +9,8 @@ // See http://www.boost.org for most recent version including documentation. // Revision History +// 21 May 01 operator= fails if operand transitively owned by *this, as in a +// linked list (report by Ken Johnson, fix by Beman Dawes) // 21 Jan 01 Suppress some useless warnings with MSVC (David Abrahams) // 19 Oct 00 Make shared_ptr ctor from auto_ptr explicit. (Robert Vugts) // 24 Jul 00 Change throw() to // never throws. See lib guidelines @@ -251,9 +253,11 @@ template class shared_ptr { void share(T* rpx, long* rpn) { if (pn != rpn) { // Q: why not px != rpx? A: fails when both == 0 + ++*rpn; // done before dispose() in case rpn transitively + // dependent on *this (bug reported by Ken Johnson) dispose(); px = rpx; - ++*(pn = rpn); + pn = rpn; } } // share }; // shared_ptr @@ -288,9 +292,11 @@ template class shared_array { shared_array& operator=(const shared_array& r) { if (pn != r.pn) { // Q: why not px != r.px? A: fails when both px == 0 + ++*r.pn; // done before dispose() in case r.pn transitively + // dependent on *this (bug reported by Ken Johnson) dispose(); px = r.px; - ++*(pn = r.pn); + pn = r.pn; } return *this; } // operator= From ac8d0f55053b04d8b0a0632cd4c8b624141abb24 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Mon, 21 May 2001 14:58:07 +0000 Subject: [PATCH 019/133] Fix doc errors, add shared_ptr_example program [SVN r10165] --- scoped_ptr.htm | 4 +- shared_ptr.htm | 30 +++---------- shared_ptr_example.cpp | 96 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 25 deletions(-) create mode 100644 shared_ptr_example.cpp diff --git a/scoped_ptr.htm b/scoped_ptr.htm index 27512d1..277b38e 100644 --- a/scoped_ptr.htm +++ b/scoped_ptr.htm @@ -106,7 +106,7 @@ output:

    Buckle my shoe

    Handle/Body Idiom

    -

    One common usage of shared_pointer is to implement a handle/body +

    One common usage of scoped_ptr is to implement a handle/body structure which avoids exposing the body (implementation) in the header file:

    class handle
     {
    @@ -123,7 +123,7 @@ body is not visible at the time scoped_ptr<> deletes it. See ISO
     5.3.5/5.  Note that some compilers will issue a warning even though the
     above code is well defined.


    -

    Revised 10 May 2001

    +

    Revised 21 May 2001

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" diff --git a/shared_ptr.htm b/shared_ptr.htm index affff12..4dd2b87 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -192,33 +192,17 @@ stored pointer.

    void swap( shared_ptr<T>& other ) throw()

    Swaps the two smart pointers, as if by std::swap.

    Class shared_ptr example

    -
    //  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).
    -
    -class Foo { ... };
    -
    -typedef boost::shared_ptr<Foo> FooPtr;
    -
    -std::vector<FooPtr> foo_vector;
    -std::set<FooPtr>    foo_set; // NOT multiset!
    -
    -...
    -{ // creation loop
    -  FooPtr foo_ptr ( new Foo( ... ) );
    -  foo_vector.push_back( foo_ptr );
    -  foo_set.insert( foo_ptr );
    -}
    -

    Note that at the termination of the creation loop, some of the FooPtr objects -may have use_count()==1 rather than use_count()==2, since foo_set is a std::set -rather than a std::multiset.  Furthermore, use_count() will be even higher -at various times inside the loop, as container operations are performed.  +

    See shared_ptr_example.cpp for a complete example program.

    +

    This program builds a std::vector and std::set of FooPtr's.

    +

    Note that after the two containers have been populated, some of the FooPtr objects +will have use_count()==1 rather than use_count()==2, since foo_set is a std::set +rather than a std::multiset.  Furthermore, 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.  Without using a smart pointer, memory and exception management would be a nightmare.


    -

    Revised 10 February, 2001 +

    Revised 21 May, 2001

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright diff --git a/shared_ptr_example.cpp b/shared_ptr_example.cpp new file mode 100644 index 0000000..988efbd --- /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; +} + From a90a157ea60dba8286401e4c300ef3182f9cd0a0 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Tue, 22 May 2001 18:58:21 +0000 Subject: [PATCH 020/133] Smart pointer and utility changes related to adding checked_delere and checked_array_delete [SVN r10189] --- include/boost/smart_ptr.hpp | 34 +++++++++++++++--------------- scoped_array.htm | 10 +++++++++ scoped_ptr.htm | 41 +++++++++++++++++++++---------------- scoped_ptr_example.cpp | 16 +++++++++++++++ scoped_ptr_example.hpp | 21 +++++++++++++++++++ scoped_ptr_example_test.cpp | 10 +++++++++ shared_array.htm | 20 ++++++++++++++++++ shared_ptr.htm | 27 ++++++++++++++++++++++-- smart_ptr.htm | 29 +++++++++++++++++++++----- 9 files changed, 167 insertions(+), 41 deletions(-) create mode 100644 scoped_ptr_example.cpp create mode 100644 scoped_ptr_example.hpp create mode 100644 scoped_ptr_example_test.cpp diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp index 2111032..3dea3f9 100644 --- a/include/boost/smart_ptr.hpp +++ b/include/boost/smart_ptr.hpp @@ -9,6 +9,7 @@ // See http://www.boost.org for most recent version including documentation. // Revision History +// 21 May 01 Require complete type on delete (suggested by Vladimir Prus) // 21 May 01 operator= fails if operand transitively owned by *this, as in a // linked list (report by Ken Johnson, fix by Beman Dawes) // 21 Jan 01 Suppress some useless warnings with MSVC (David Abrahams) @@ -54,8 +55,9 @@ #include // for std::size_t #include // for std::auto_ptr #include // for std::swap -#include // for boost::noncopyable +#include // for boost::noncopyable, checked_delete, checked_array_delete #include // for std::less +#include // for BOOST_STATIC_ASSERT namespace boost { @@ -74,9 +76,8 @@ template class scoped_ptr : noncopyable { typedef T element_type; explicit scoped_ptr( T* p=0 ) : ptr(p) {} // never throws - ~scoped_ptr() { delete ptr; } - - void reset( T* p=0 ) { if ( ptr != p ) { delete ptr; ptr = p; } } + ~scoped_ptr() { checked_delete(ptr); } + void reset( T* p=0 ) { if ( ptr != p ) { checked_delete(ptr); ptr = p; } } T& operator*() const { return *ptr; } // never throws #ifdef BOOST_MSVC # pragma warning(push) @@ -107,9 +108,10 @@ template class scoped_array : noncopyable { typedef T element_type; explicit scoped_array( T* p=0 ) : ptr(p) {} // never throws - ~scoped_array() { delete [] ptr; } + ~scoped_array() { checked_array_delete(ptr); } - void reset( T* p=0 ) { if ( ptr != p ) {delete [] ptr; ptr=p;} } + void reset( T* p=0 ) { if ( ptr != p ) + {checked_array_delete(ptr); ptr=p;} } T* get() const { return ptr; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION @@ -132,7 +134,7 @@ template class shared_ptr { explicit shared_ptr(T* p =0) : px(p) { try { pn = new long(1); } // fix: prevent leak if new throws - catch (...) { delete p; throw; } + catch (...) { checked_delete(p); throw; } } shared_ptr(const shared_ptr& r) : px(r.px) { ++*(pn = r.pn); } // never throws @@ -167,7 +169,7 @@ template class shared_ptr { template shared_ptr& operator=(std::auto_ptr& r) { // code choice driven by guarantee of "no effect if new throws" - if (*pn == 1) { delete px; } + if (*pn == 1) { checked_delete(px); } else { // allocate new reference counter long * tmp = new long(1); // may throw --*pn; // only decrement once danger of new throwing is past @@ -186,7 +188,7 @@ template class shared_ptr { shared_ptr& operator=(std::auto_ptr& r) { // code choice driven by guarantee of "no effect if new throws" - if (*pn == 1) { delete px; } + if (*pn == 1) { checked_delete(px); } else { // allocate new reference counter long * tmp = new long(1); // may throw --*pn; // only decrement once danger of new throwing is past @@ -200,12 +202,12 @@ template class shared_ptr { void reset(T* p=0) { if ( px == p ) return; // fix: self-assignment safe - if (--*pn == 0) { delete px; } + if (--*pn == 0) { checked_delete(px); } else { // allocate new reference counter try { pn = new long; } // fix: prevent leak if new throws catch (...) { ++*pn; // undo effect of --*pn above to meet effects guarantee - delete p; + checked_delete(p); throw; } // catch } // allocate new reference counter @@ -249,7 +251,7 @@ template class shared_ptr { template friend class shared_ptr; #endif - void dispose() { if (--*pn == 0) { delete px; delete pn; } } + void dispose() { if (--*pn == 0) { checked_delete(px); delete pn; } } void share(T* rpx, long* rpn) { if (pn != rpn) { // Q: why not px != rpx? A: fails when both == 0 @@ -282,7 +284,7 @@ template class shared_array { explicit shared_array(T* p =0) : px(p) { try { pn = new long(1); } // fix: prevent leak if new throws - catch (...) { delete [] p; throw; } + catch (...) { checked_array_delete(p); throw; } } shared_array(const shared_array& r) : px(r.px) // never throws @@ -303,12 +305,12 @@ template class shared_array { void reset(T* p=0) { if ( px == p ) return; // fix: self-assignment safe - if (--*pn == 0) { delete [] px; } + if (--*pn == 0) { checked_array_delete(px); } else { // allocate new reference counter try { pn = new long; } // fix: prevent leak if new throws catch (...) { ++*pn; // undo effect of --*pn above to meet effects guarantee - delete [] p; + checked_array_delete(p); throw; } // catch } // allocate new reference counter @@ -335,7 +337,7 @@ template class shared_array { T* px; // contained pointer long* pn; // ptr to reference counter - void dispose() { if (--*pn == 0) { delete [] px; delete pn; } } + void dispose() { if (--*pn == 0) { checked_array_delete(px); delete pn; } } }; // shared_array diff --git a/scoped_array.htm b/scoped_array.htm index e317e21..f146ee2 100644 --- a/scoped_array.htm +++ b/scoped_array.htm @@ -59,19 +59,27 @@ template<typename T> class scoped_array : Common Requirements.

    scoped_array destructor

    ~scoped_array();
    +

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    Deletes the array pointed to by the stored pointer.  Note that in C++ delete[] on a pointer with a value of 0 is harmless.

    Does not throw exceptions.

    scoped_array reset

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

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    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.

    Does not throw exceptions.

    scoped_array operator[]

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

    +

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    Returns a reference to element i of the array pointed to by the stored pointer.

    Behavior is undefined (and almost certainly undesirable) if get()==0, @@ -79,6 +87,8 @@ or if i is less than 0 or is greater or equal to the number of elements in the array.

    scoped_array get

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

    T is not required be a complete type at point of instantiation.  +See Common Requirements.

    Returns the stored pointer.

    Class scoped_array example

    [To be supplied. In the meantime, see smart_ptr_test.cpp.]

    diff --git a/scoped_ptr.htm b/scoped_ptr.htm index 277b38e..4945084 100644 --- a/scoped_ptr.htm +++ b/scoped_ptr.htm @@ -59,25 +59,38 @@ template<typename T> class scoped_ptr : scoped_ptr constructors
    explicit scoped_ptr( T* p=0 );  // never throws
    +

    T is not required be a complete type at point of instantiation.  +See Common Requirements.

    Constructs a scoped_ptr, storing a copy of p, which must -have been allocated via a C++ new expression or be 0..

    +have been allocated via a C++ new expression or be 0.

    scoped_ptr destructor

    ~scoped_ptr();
    +

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    Deletes the object pointed to by the stored pointer.  Note that in C++, delete on a pointer with a value of 0 is harmless.

    Does not throw exceptions.

    scoped_ptr reset

    void reset( T* p=0 );
    +

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    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.

    Does not throw exceptions.

    scoped_ptr operator*

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

    T is required be a complete type at point of instantiation.  See Common +Requirements.

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

    scoped_ptr operator-> and get

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

    T is required be a complete type at point of instantiation of +operator->().  See Common +Requirements.

    +

    T is not required be a complete type at point of instantiation of +get().  See Common Requirements.

    Both return the stored pointer.

    Class scoped_ptr examples

    #include <iostream>
    @@ -106,24 +119,16 @@ output:

    Buckle my shoe

    Handle/Body Idiom

    -

    One common usage of scoped_ptr is to implement a handle/body -structure which avoids exposing the body (implementation) in the header file:

    -
    class handle
    -{
    -public:    // simple forwarding functions to the body class
    -    void f();
    -    void g(int);
    -private:
    -    friend class body;  //incomplete class hides implementation
    -    boost::scoped_ptr<body> imp;
    -};
    -

    This code requires that class body have a trivial destructor to -avoid undefined behavior.  This is because the definition of class -body is not visible at the time scoped_ptr<> deletes it. See ISO -5.3.5/5.  Note that some compilers will issue a warning even though the -above code is well defined.

    +

    One common usage of scoped_ptr is to implement a handle/body 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. 


    -

    Revised 21 May 2001

    +

    Revised 22 May 2001

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" 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..97c8bff --- /dev/null +++ b/scoped_ptr_example.hpp @@ -0,0 +1,21 @@ +// Boost scoped_ptr_example header file ------------------------------------// + +#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 : 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..3629ec8 --- /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; +} \ No newline at end of file diff --git a/shared_array.htm b/shared_array.htm index 89d9339..24842d1 100644 --- a/shared_array.htm +++ b/shared_array.htm @@ -108,17 +108,23 @@ name BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION is defined.

    Provides the type of the stored pointer.

    shared_array constructors

    explicit shared_array( T* p=0 );
    +

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    Constructs a shared_array, storing a copy of p, which must have been allocated via a C++ new[] expression or be 0. Afterwards, use_count() is 1 (even if p==0; see ~shared_array).

    The only exception which may be thrown is std::bad_alloc.  If an exception is thrown,  delete[] p is called.

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

    T is not required be a complete type at point of instantiation.  +See Common Requirements.

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

    shared_array destructor

    ~shared_array();
    +

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    If use_count() == 1, deletes the array pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. Note that in C++ delete[] on a pointer with @@ -126,6 +132,8 @@ a value of 0 is harmless.

    Does not throw exceptions.

    shared_array operator=

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

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    First, if use_count() == 1, deletes the array pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. Note that in C++ delete[] on a @@ -135,6 +143,8 @@ of the pointer stored in r. Afterwards, use_count()r.use_count()

    shared_array reset

    void reset( T* p=0 );
    +

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    First, if use_count() == 1, deletes the array pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. Note that in C++  delete[] @@ -147,6 +157,8 @@ see ~shared_array).

    an exception is thrown,  delete[] p is called.

    shared_array operator[]

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

    +

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    Returns a reference to element i of the array pointed to by the stored pointer.

    Behavior is undefined (and almost certainly undesirable) if get()==0, @@ -154,16 +166,24 @@ or if i is less than 0 or is greater or equal to the number of elements in the array.

    shared_array get

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

    T is not required be a complete type at point of instantiation.  +See Common Requirements.

    Returns the stored pointer.

    shared_array use_count

    long use_count() const; // never throws

    +

    T is not required be a complete type at point of instantiation.  +See Common Requirements.

    Returns the number of shared_arrays sharing ownership of the stored pointer.

    shared_array unique

    bool unique() const; // never throws

    +

    T is not required be a complete type at point of instantiation.  +See Common Requirements.

    Returns use_count() == 1.

    shared_array swap

    void swap( shared_array<T>& other ) throw()

    +

    T is not required be a complete type at point of instantiation.  +See Common Requirements.

    Swaps the two smart pointers, as if by std::swap.

    Class shared_array example

    [To be supplied. In the meantime, see smart_ptr_test.cpp.]

    diff --git a/shared_ptr.htm b/shared_ptr.htm index 4dd2b87..78ed702 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -118,6 +118,8 @@ the macro name BOOST_NO_MEMBER_TEMPLATES is defined.

    Provides the type of the stored pointer.

    shared_ptr constructors

    explicit shared_ptr( T* p=0 );
    +

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    Constructs a shared_ptr, storing a copy of p, which must have been allocated via a C++ new expression or be 0. Afterwards, use_count() is 1 (even if p==0; see ~shared_ptr).

    @@ -128,6 +130,8 @@ template<typename Y> shared_ptr(const shared_ptr<Y>& r); // never throws template<typename Y> shared_ptr(std::auto_ptr<Y>& r);
    +

    T is not required be a complete type at point of instantiation.  +See Common Requirements.

    Constructs a shared_ptr, as if by storing a copy of the pointer stored in r. Afterwards, use_count() for all copies is 1 more than the initial r.use_count(), or 1 @@ -138,6 +142,8 @@ is std::bad_alloc.   If an exception is thrown, that constructor has no effect.

    shared_ptr destructor

    ~shared_ptr();
    +

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    If use_count() == 1, deletes the object pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. Note that in C++  delete on a pointer @@ -149,6 +155,8 @@ template<typename Y> shared_ptr& operator=(const shared_ptr<Y>& r); template<typename Y> shared_ptr& operator=(std::auto_ptr<Y>& r); +

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    First, if use_count() == 1, deletes the object pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. Note that in C++  delete on @@ -164,6 +172,8 @@ is std::bad_alloc.   If an exception is thrown, the function has no effect.

    shared_ptr reset

    void reset( T* p=0 );
    +

    T is required be a complete type at point of instantiation.  See Common +Requirements.

    First, if use_count() == 1, deletes the object pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. 

    @@ -176,33 +186,46 @@ on a pointer with a value of 0 is harmless.

    an exception is thrown,  delete p is called.

    shared_ptr operator*

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

    T is required be a complete type at point of instantiation.  See Common +Requirements.

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

    shared_ptr operator-> and get

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

    T is required be a complete type at point of instantiation of +operator->().  See Common +Requirements.

    +

    T is not required be a complete type at point of instantiation of +get().  See Common Requirements.

    Both return the stored pointer.

    shared_ptr use_count

    long use_count() const; // never throws

    +

    T is not required be a complete type at point of instantiation.  +See Common Requirements.

    Returns the number of shared_ptrs sharing ownership of the stored pointer.

    shared_ptr unique

    bool unique() const; // never throws

    +

    T is not required be a complete type at point of instantiation.  +See Common Requirements.

    Returns use_count() == 1.

    shared_ptr swap

    void swap( shared_ptr<T>& other ) throw()

    +

    T is not required be a complete type at point of instantiation.  +See Common Requirements.

    Swaps the two smart pointers, as if by std::swap.

    Class shared_ptr example

    See shared_ptr_example.cpp for a complete example program.

    This program builds a std::vector and std::set of FooPtr's.

    Note that after the two containers have been populated, some of the FooPtr objects will have use_count()==1 rather than use_count()==2, since foo_set is a std::set -rather than a std::multiset.  Furthermore, use_count() may be even higher +rather than a std::multiset, and thus does not contain duplicate entries.  Furthermore, 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.  Without using a smart pointer, memory and exception management would be a nightmare.


    -

    Revised 21 May, 2001 +

    Revised 22 May, 2001

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright diff --git a/smart_ptr.htm b/smart_ptr.htm index dc5db1f..b7bcf04 100644 --- a/smart_ptr.htm +++ b/smart_ptr.htm @@ -27,11 +27,11 @@ provides four smart pointer template classes:

    scoped_ptr - Simple sole ownership of single objects. + Simple sole ownership of single objects. Noncopyable. scoped_array - Simple sole ownership of arrays. + Simple sole ownership of arrays. Noncopyable. shared_ptr @@ -53,10 +53,25 @@ provided to verify correct operation.

    A page on Smart Pointer Timings will be of interest to those curious about performance issues.

    Common requirements

    -

    These smart pointer classes have a template parameter, T, which +

    These smart pointer classes have a template parameter, T, which specifies the type of the object pointed to by the smart pointer.  The behavior of all four classes is undefined if the destructor or operator delete -for objects of type T throws exceptions.

    +for objects of type T throws 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 point of instantiation of all member functions.

    +

    Rationale

    +

    The requirements on T are carefully crafted to ensure safety +yet allow handle-body (aka 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.

    +

    Example

    +

    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.   The +instantiation of member functions which require a complete type occurs in the scoped_ptr_example.cpp +implementation file. 

    Exception safety

    Several functions in these smart pointer classes are specified as having "no effect" or "no effect except such-and-such" if an @@ -78,6 +93,10 @@ never throws.

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

    History and acknowledgements

    +

    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

    @@ -125,7 +144,7 @@ implementation.

    See the Revision History section of the header for further contributors.


    Revised  27 Jul 200022 May 2001

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright From 7c09884eacafeb8c83b4ec2b2a7d98764dd5d86a Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Wed, 23 May 2001 20:14:15 +0000 Subject: [PATCH 021/133] Move MS VC++ pragmas to workaround compiler crash reported by several people with SP4 and SP5. [SVN r10204] --- include/boost/smart_ptr.hpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp index 3dea3f9..0ec807b 100644 --- a/include/boost/smart_ptr.hpp +++ b/include/boost/smart_ptr.hpp @@ -9,7 +9,8 @@ // See http://www.boost.org for most recent version including documentation. // Revision History -// 21 May 01 Require complete type on delete (suggested by Vladimir Prus) +// 21 May 01 Require complete type where incomplete type is unsafe. +// (suggested by Vladimir Prus) // 21 May 01 operator= fails if operand transitively owned by *this, as in a // linked list (report by Ken Johnson, fix by Beman Dawes) // 21 Jan 01 Suppress some useless warnings with MSVC (David Abrahams) @@ -59,6 +60,11 @@ #include // for std::less #include // for BOOST_STATIC_ASSERT +#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash +# pragma warning(push) +# pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation +#endif + namespace boost { // scoped_ptr --------------------------------------------------------------// @@ -80,13 +86,7 @@ template class scoped_ptr : noncopyable { void reset( T* p=0 ) { if ( ptr != p ) { checked_delete(ptr); ptr = p; } } T& operator*() const { return *ptr; } // never throws #ifdef BOOST_MSVC -# pragma warning(push) -# pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation -#endif T* operator->() const { return ptr; } // never throws -#ifdef BOOST_MSVC -# pragma warning(pop) -#endif T* get() const { return ptr; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! @@ -216,14 +216,7 @@ template class shared_ptr { } // reset T& operator*() const { return *px; } // never throws -#ifdef BOOST_MSVC -# pragma warning(push) -# pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation -#endif T* operator->() const { return px; } // never throws -#ifdef BOOST_MSVC -# pragma warning(pop) -#endif T* get() const { return px; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! @@ -397,6 +390,10 @@ template #endif // ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + #endif // BOOST_SMART_PTR_HPP From 94287044ba41125fe689417a65a35a1d03859e5a Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 24 May 2001 01:32:07 +0000 Subject: [PATCH 022/133] Oops! Fix boo boo from prior fix [SVN r10206] --- include/boost/smart_ptr.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp index 0ec807b..442598b 100644 --- a/include/boost/smart_ptr.hpp +++ b/include/boost/smart_ptr.hpp @@ -85,7 +85,6 @@ template class scoped_ptr : noncopyable { ~scoped_ptr() { checked_delete(ptr); } void reset( T* p=0 ) { if ( ptr != p ) { checked_delete(ptr); ptr = p; } } T& operator*() const { return *ptr; } // never throws -#ifdef BOOST_MSVC T* operator->() const { return ptr; } // never throws T* get() const { return ptr; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION From c17921c417413ac11041b04f7ed23a5d435ce09a Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 24 May 2001 18:42:25 +0000 Subject: [PATCH 023/133] Documentation and example program improvements [SVN r10220] --- scoped_array.htm | 17 ++-- scoped_ptr.htm | 55 ++++++----- shared_array.htm | 29 ++---- shared_ptr.htm | 49 +++++----- smart_ptr.htm | 22 ++--- smart_ptr_test.cpp | 228 +++++++++++++++++++++++++-------------------- 6 files changed, 214 insertions(+), 186 deletions(-) diff --git a/scoped_array.htm b/scoped_array.htm index f146ee2..518b4cb 100644 --- a/scoped_array.htm +++ b/scoped_array.htm @@ -34,7 +34,7 @@ for that usage.

    pointed to.   T must meet the smart pointer common requirements.

    Class scoped_array Synopsis

    -
    #include <boost/smart_ptr.hpp>
    +
    #include <boost/smart_ptr.hpp>
     namespace boost {
     
     template<typename T> class scoped_array : noncopyable {
    @@ -59,27 +59,21 @@ template<typename T> class scoped_array : Common Requirements.

    scoped_array destructor

    ~scoped_array();
    -

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    Deletes the array pointed to by the stored pointer.  Note that in C++ delete[] on a pointer with a value of 0 is harmless.

    Does not throw exceptions.

    scoped_array reset

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

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    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.

    Does not throw exceptions.

    scoped_array operator[]

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

    -

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    Returns a reference to element i of the array pointed to by the stored pointer.

    Behavior is undefined (and almost certainly undesirable) if get()==0, @@ -87,13 +81,16 @@ or if i is less than 0 or is greater or equal to the number of elements in the array.

    scoped_array get

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

    T is not required be a complete type at point of instantiation.  +

    T is not required be a complete type.  See Common Requirements.

    Returns the stored pointer.

    Class scoped_array example

    [To be supplied. In the meantime, see smart_ptr_test.cpp.]


    -

    Revised  December 8, 1999

    +

    Revised  24 May, 2001 +

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" diff --git a/scoped_ptr.htm b/scoped_ptr.htm index 4945084..652d1bb 100644 --- a/scoped_ptr.htm +++ b/scoped_ptr.htm @@ -19,13 +19,16 @@ See example.

    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.  By -being noncopyable, it is -safer than shared_ptr or std::auto_ptr for pointers which should not be +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 so simple, in its usual implementation every operation is as fast as for a built-in pointer and it has no more space overhead -that a built-in pointer.

    +that a built-in pointer.  (Because of the "complete type" +requirement for delete and reset members, they may have one additional function +call overhead in certain idioms.  See Handle/Body +Idiom.)   

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

    Class scoped_ptr cannot correctly hold a pointer to a @@ -35,7 +38,7 @@ for that usage.

    pointed to.   T must meet the smart pointer common requirements.

    Class scoped_ptr Synopsis

    -
    #include <boost/smart_ptr.hpp>
    +
    #include <boost/smart_ptr.hpp>
     namespace boost {
     
     template<typename T> class scoped_ptr : noncopyable {
    @@ -59,38 +62,28 @@ template<typename T> class scoped_ptr : scoped_ptr constructors
     
    explicit scoped_ptr( T* p=0 );  // never throws
    -

    T is not required be a complete type at point of instantiation.  +

    T is not required be a complete type.  See Common Requirements.

    Constructs a scoped_ptr, storing a copy of p, which must have been allocated via a C++ new expression or be 0.

    scoped_ptr destructor

    ~scoped_ptr();
    -

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    Deletes the object pointed to by the stored pointer.  Note that in C++, delete on a pointer with a value of 0 is harmless.

    Does not throw exceptions.

    scoped_ptr reset

    void reset( T* p=0 );
    -

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    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.

    Does not throw exceptions.

    scoped_ptr operator*

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

    T is required be a complete type at point of instantiation.  See Common -Requirements.

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

    scoped_ptr operator-> and get

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

    T is required be a complete type at point of instantiation of -operator->().  See Common -Requirements.

    -

    T is not required be a complete type at point of instantiation of -get().  See Common Requirements.

    +

    T is not required by get() be a complete type.  See Common Requirements.

    Both return the stored pointer.

    Class scoped_ptr examples

    #include <iostream>
    @@ -118,17 +111,37 @@ output:

    2 Buckle my shoe
    -

    Handle/Body Idiom

    -

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

    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 actually 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 - you are signaling intent.

    +

    It has been suggested that boost::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. 

    +implementation file.

    +

    FAQ

    +

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


    -

    Revised 22 May 2001

    +

    Revised 24 May 2001

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" diff --git a/shared_array.htm b/shared_array.htm index 24842d1..6de8704 100644 --- a/shared_array.htm +++ b/shared_array.htm @@ -30,13 +30,13 @@ structures. For example, if main() holds a shared_array pointing to array A, which directly or indirectly holds a shared_array pointing back to array A, then array A's use_count() will be 2, and destruction of the main() shared_array will leave array A dangling with a use_count() of 1.

    -

    A heavier duty alternative to a shared_array is a shared_ptr -to a C++ Standard Library vector.

    +

    A C++ Standard Library vector is a +heavier duty alternative to a shared_array.

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

    Class shared_array Synopsis

    -
    #include <boost/smart_ptr.hpp>
    +
    #include <boost/smart_ptr.hpp>
     namespace boost {
     
     template<typename T> class shared_array {
    @@ -108,23 +108,17 @@ name BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION is defined.

    Provides the type of the stored pointer.

    shared_array constructors

    explicit shared_array( T* p=0 );
    -

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    Constructs a shared_array, storing a copy of p, which must have been allocated via a C++ new[] expression or be 0. Afterwards, use_count() is 1 (even if p==0; see ~shared_array).

    The only exception which may be thrown is std::bad_alloc.  If an exception is thrown,  delete[] p is called.

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

    T is not required be a complete type at point of instantiation.  -See Common Requirements.

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

    shared_array destructor

    ~shared_array();
    -

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    If use_count() == 1, deletes the array pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. Note that in C++ delete[] on a pointer with @@ -132,8 +126,6 @@ a value of 0 is harmless.

    Does not throw exceptions.

    shared_array operator=

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

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    First, if use_count() == 1, deletes the array pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. Note that in C++ delete[] on a @@ -143,8 +135,6 @@ of the pointer stored in r. Afterwards, use_count()r.use_count()

    shared_array reset

    void reset( T* p=0 );
    -

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    First, if use_count() == 1, deletes the array pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. Note that in C++  delete[] @@ -157,8 +147,6 @@ see ~shared_array).

    an exception is thrown,  delete[] p is called.

    shared_array operator[]

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

    -

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    Returns a reference to element i of the array pointed to by the stored pointer.

    Behavior is undefined (and almost certainly undesirable) if get()==0, @@ -166,29 +154,30 @@ or if i is less than 0 or is greater or equal to the number of elements in the array.

    shared_array get

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

    T is not required be a complete type at point of instantiation.  +

    T is not required be a complete type.  See Common Requirements.

    Returns the stored pointer.

    shared_array use_count

    long use_count() const; // never throws

    -

    T is not required be a complete type at point of instantiation.  +

    T is not required be a complete type.  See Common Requirements.

    Returns the number of shared_arrays sharing ownership of the stored pointer.

    shared_array unique

    bool unique() const; // never throws

    -

    T is not required be a complete type at point of instantiation.  +

    T is not required be a complete type.  See Common Requirements.

    Returns use_count() == 1.

    shared_array swap

    void swap( shared_array<T>& other ) throw()

    -

    T is not required be a complete type at point of instantiation.  +

    T is not required be a complete type.  See Common Requirements.

    Swaps the two smart pointers, as if by std::swap.

    Class shared_array example

    [To be supplied. In the meantime, see smart_ptr_test.cpp.]


    -

    Revised December 8, 1999

    +

    Revised 24 May, 2001 +

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" diff --git a/shared_ptr.htm b/shared_ptr.htm index 78ed702..cdf2b93 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -34,7 +34,7 @@ object A dangling with a use_count() of 1.

    pointed to.   T must meet the smart pointer Common requirements.

    Class shared_ptr Synopsis

    -
    #include <boost/smart_ptr.hpp>
    +
    #include <boost/smart_ptr.hpp>
     namespace boost {
     
     template<typename T> class shared_ptr {
    @@ -118,8 +118,6 @@ the macro name BOOST_NO_MEMBER_TEMPLATES is defined.

    Provides the type of the stored pointer.

    shared_ptr constructors

    explicit shared_ptr( T* p=0 );
    -

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    Constructs a shared_ptr, storing a copy of p, which must have been allocated via a C++ new expression or be 0. Afterwards, use_count() is 1 (even if p==0; see ~shared_ptr).

    @@ -130,8 +128,6 @@ template<typename Y> shared_ptr(const shared_ptr<Y>& r); // never throws template<typename Y> shared_ptr(std::auto_ptr<Y>& r);
    -

    T is not required be a complete type at point of instantiation.  -See Common Requirements.

    Constructs a shared_ptr, as if by storing a copy of the pointer stored in r. Afterwards, use_count() for all copies is 1 more than the initial r.use_count(), or 1 @@ -142,8 +138,6 @@ is std::bad_alloc.   If an exception is thrown, that constructor has no effect.

    shared_ptr destructor

    ~shared_ptr();
    -

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    If use_count() == 1, deletes the object pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. Note that in C++  delete on a pointer @@ -155,8 +149,6 @@ template<typename Y> shared_ptr& operator=(const shared_ptr<Y>& r); template<typename Y> shared_ptr& operator=(std::auto_ptr<Y>& r);

    -

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    First, if use_count() == 1, deletes the object pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. Note that in C++  delete on @@ -172,8 +164,6 @@ is std::bad_alloc.   If an exception is thrown, the function has no effect.

    shared_ptr reset

    void reset( T* p=0 );
    -

    T is required be a complete type at point of instantiation.  See Common -Requirements.

    First, if use_count() == 1, deletes the object pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. 

    @@ -186,32 +176,26 @@ on a pointer with a value of 0 is harmless.

    an exception is thrown,  delete p is called.

    shared_ptr operator*

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

    T is required be a complete type at point of instantiation.  See Common -Requirements.

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

    shared_ptr operator-> and get

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

    T is required be a complete type at point of instantiation of -operator->().  See Common -Requirements.

    -

    T is not required be a complete type at point of instantiation of -get().  See Common Requirements.

    +

    T is not required by get() to be a complete type .  See Common Requirements.

    Both return the stored pointer.

    shared_ptr use_count

    long use_count() const; // never throws

    -

    T is not required be a complete type at point of instantiation.  +

    T is not required be a complete type.  See Common Requirements.

    Returns the number of shared_ptrs sharing ownership of the stored pointer.

    shared_ptr unique

    bool unique() const; // never throws

    -

    T is not required be a complete type at point of instantiation.  +

    T is not required be a complete type.  See Common Requirements.

    Returns use_count() == 1.

    shared_ptr swap

    void swap( shared_ptr<T>& other ) throw()

    -

    T is not required be a complete type at point of instantiation.  +

    T is not required be a complete type.  See Common Requirements.

    Swaps the two smart pointers, as if by std::swap.

    Class shared_ptr example

    @@ -224,8 +208,29 @@ at various times while push_back() and insert() container operations are perform More complicated yet, the container operations may throw exceptions under a variety of circumstances.  Without using a smart pointer, memory and exception management 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.

    +

    FAQ

    +

    Q. Why doesn't shared_ptr have template parameters supplying +traits or policies to allow extensive user customization?
    +A. Parameterization discourages users.  Shared_ptr is +carefully crafted to meet common needs without extensive parameterization. +Someday a highly configurable smart pointer may be invented that is also very +easy to use and very hard to misuse.  Until then, shared_ptr is the +smart pointer of choice for a wide range of applications.

    +

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


    -

    Revised 22 May, 2001 +

    Revised 24 May, 2001

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright diff --git a/smart_ptr.htm b/smart_ptr.htm index b7bcf04..07538e4 100644 --- a/smart_ptr.htm +++ b/smart_ptr.htm @@ -56,22 +56,20 @@ interest to those curious about performance issues.

    These smart pointer classes have a template parameter, T, which specifies the type of the object pointed to by the smart pointer.  The behavior of all four classes is undefined if the destructor or operator delete -for objects of type T throws exceptions.

    +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 point of instantiation of all member functions.

    +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 checked_delete().

    Rationale

    -

    The requirements on T are carefully crafted to ensure safety -yet allow handle-body (aka pimpl) and similar idioms.  In these idioms a +

    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.

    -

    Example

    -

    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.   The -instantiation of member functions which require a complete type occurs in the scoped_ptr_example.cpp -implementation file. 

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

    Exception safety

    Several functions in these smart pointer classes are specified as having "no effect" or "no effect except such-and-such" if an @@ -144,7 +142,7 @@ implementation.

    See the Revision History section of the header for further contributors.


    Revised  22 May 200124 May 2001

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright diff --git a/smart_ptr_test.cpp b/smart_ptr_test.cpp index cd4d61b..62c97ca 100644 --- a/smart_ptr_test.cpp +++ b/smart_ptr_test.cpp @@ -6,20 +6,26 @@ // implied warranty, and with no claim as to its suitability for any purpose. // Revision History +// 24 May 01 use Boost test library for error detection, reporting, add tests +// for operations on incomplete types (Beman Dawes) // 29 Nov 99 added std::swap and associative container tests (Darin Adler) // 25 Sep 99 added swap tests // 20 Jul 99 header name changed to .hpp // 20 Apr 99 additional error tests added. +#define BOOST_INCLUDE_MAIN +#include #include -#include #include #include #include -#ifdef NDEBUG -#error This test program makes no sense if NDEBUG is defined -#endif +class Incomplete; + +Incomplete * get_ptr( boost::shared_ptr& incomplete ) +{ + return incomplete.get(); +} using namespace std; using boost::scoped_ptr; @@ -28,7 +34,7 @@ using boost::shared_ptr; using boost::shared_array; template -void ck( const T* v1, T v2 ) { assert( *v1 == v2 ); } +void ck( const T* v1, T v2 ) { BOOST_TEST( *v1 == v2 ); } namespace { int UDT_use_count; // independent of pointer maintained counts @@ -48,169 +54,189 @@ class UDT { 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() << endl; + return incomplete.get(); +} // main --------------------------------------------------------------------// // This isn't a very systematic test; it just hits some of the basics. -int main() { +int test_main( int, char ** ) { - assert( UDT_use_count == 0 ); // reality check + BOOST_TEST( UDT_use_count == 0 ); // reality check // test scoped_ptr with a built-in type long * lp = new long; scoped_ptr sp ( lp ); - assert( sp.get() == lp ); - assert( lp == sp.get() ); - assert( &*sp == lp ); + BOOST_TEST( sp.get() == lp ); + BOOST_TEST( lp == sp.get() ); + BOOST_TEST( &*sp == lp ); *sp = 1234568901L; - assert( *sp == 1234568901L ); - assert( *lp == 1234568901L ); + BOOST_TEST( *sp == 1234568901L ); + BOOST_TEST( *lp == 1234568901L ); ck( static_cast(sp.get()), 1234568901L ); ck( lp, *sp ); sp.reset(); - assert( sp.get() == 0 ); + BOOST_TEST( sp.get() == 0 ); // test scoped_ptr with a user defined type scoped_ptr udt_sp ( new UDT( 999888777 ) ); - assert( udt_sp->value() == 999888777 ); + BOOST_TEST( udt_sp->value() == 999888777 ); udt_sp.reset(); udt_sp.reset( new UDT( 111222333 ) ); - assert( udt_sp->value() == 111222333 ); + BOOST_TEST( udt_sp->value() == 111222333 ); udt_sp.reset( new UDT( 333222111 ) ); - assert( udt_sp->value() == 333222111 ); + BOOST_TEST( udt_sp->value() == 333222111 ); // test scoped_array with a build-in type char * sap = new char [ 100 ]; scoped_array sa ( sap ); - assert( sa.get() == sap ); - assert( sap == sa.get() ); + BOOST_TEST( sa.get() == sap ); + BOOST_TEST( sap == sa.get() ); strcpy( sa.get(), "Hot Dog with mustard and relish" ); - assert( strcmp( sa.get(), "Hot Dog with mustard and relish" ) == 0 ); - assert( strcmp( sap, "Hot Dog with mustard and relish" ) == 0 ); + BOOST_TEST( strcmp( sa.get(), "Hot Dog with mustard and relish" ) == 0 ); + BOOST_TEST( strcmp( sap, "Hot Dog with mustard and relish" ) == 0 ); - assert( sa[0] == 'H' ); - assert( sa[30] == 'h' ); + BOOST_TEST( sa[0] == 'H' ); + BOOST_TEST( sa[30] == 'h' ); sa[0] = 'N'; sa[4] = 'd'; - assert( strcmp( sap, "Not dog with mustard and relish" ) == 0 ); + BOOST_TEST( strcmp( sap, "Not dog with mustard and relish" ) == 0 ); sa.reset(); - assert( sa.get() == 0 ); + BOOST_TEST( sa.get() == 0 ); // test shared_ptr with a built-in type int * ip = new int; shared_ptr cp ( ip ); - assert( ip == cp.get() ); - assert( cp.use_count() == 1 ); + BOOST_TEST( ip == cp.get() ); + BOOST_TEST( cp.use_count() == 1 ); *cp = 54321; - assert( *cp == 54321 ); - assert( *ip == 54321 ); + BOOST_TEST( *cp == 54321 ); + BOOST_TEST( *ip == 54321 ); ck( static_cast(cp.get()), 54321 ); ck( static_cast(ip), *cp ); shared_ptr cp2 ( cp ); - assert( ip == cp2.get() ); - assert( cp.use_count() == 2 ); - assert( cp2.use_count() == 2 ); + BOOST_TEST( ip == cp2.get() ); + BOOST_TEST( cp.use_count() == 2 ); + BOOST_TEST( cp2.use_count() == 2 ); - assert( *cp == 54321 ); - assert( *cp2 == 54321 ); + BOOST_TEST( *cp == 54321 ); + BOOST_TEST( *cp2 == 54321 ); ck( static_cast(cp2.get()), 54321 ); ck( static_cast(ip), *cp2 ); shared_ptr cp3 ( cp ); - assert( cp.use_count() == 3 ); - assert( cp2.use_count() == 3 ); - assert( cp3.use_count() == 3 ); + BOOST_TEST( cp.use_count() == 3 ); + BOOST_TEST( cp2.use_count() == 3 ); + BOOST_TEST( cp3.use_count() == 3 ); cp.reset(); - assert( cp2.use_count() == 2 ); - assert( cp3.use_count() == 2 ); - assert( cp.use_count() == 1 ); + BOOST_TEST( cp2.use_count() == 2 ); + BOOST_TEST( cp3.use_count() == 2 ); + BOOST_TEST( cp.use_count() == 1 ); cp.reset( new int ); *cp = 98765; - assert( *cp == 98765 ); + BOOST_TEST( *cp == 98765 ); *cp3 = 87654; - assert( *cp3 == 87654 ); - assert( *cp2 == 87654 ); + BOOST_TEST( *cp3 == 87654 ); + BOOST_TEST( *cp2 == 87654 ); cp.swap( cp3 ); - assert( *cp == 87654 ); - assert( *cp2 == 87654 ); - assert( *cp3 == 98765 ); + BOOST_TEST( *cp == 87654 ); + BOOST_TEST( *cp2 == 87654 ); + BOOST_TEST( *cp3 == 98765 ); cp.swap( cp3 ); - assert( *cp == 98765 ); - assert( *cp2 == 87654 ); - assert( *cp3 == 87654 ); + BOOST_TEST( *cp == 98765 ); + BOOST_TEST( *cp2 == 87654 ); + BOOST_TEST( *cp3 == 87654 ); cp2 = cp2; - assert( cp2.use_count() == 2 ); - assert( *cp2 == 87654 ); + BOOST_TEST( cp2.use_count() == 2 ); + BOOST_TEST( *cp2 == 87654 ); cp = cp2; - assert( cp2.use_count() == 3 ); - assert( *cp2 == 87654 ); - assert( cp.use_count() == 3 ); - assert( *cp == 87654 ); + 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 ); - assert( cp4.use_count() == 3 ); - assert( *cp4 == 87654 ); - assert( cp2.get() == 0 ); + BOOST_TEST( cp4.use_count() == 3 ); + BOOST_TEST( *cp4 == 87654 ); + BOOST_TEST( cp2.get() == 0 ); #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION set< shared_ptr > scp; scp.insert(cp4); - assert( scp.find(cp4) != scp.end() ); - assert( scp.find(cp4) == scp.find( shared_ptr(cp4) ) ); + BOOST_TEST( scp.find(cp4) != scp.end() ); + BOOST_TEST( scp.find(cp4) == scp.find( shared_ptr(cp4) ) ); #endif // test shared_array with a built-in type char * cap = new char [ 100 ]; shared_array ca ( cap ); - assert( ca.get() == cap ); - assert( cap == ca.get() ); - assert( &ca[0] == 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" ); - assert( strcmp( ca.get(), "Hot Dog with mustard and relish" ) == 0 ); - assert( strcmp( cap, "Hot Dog with mustard and relish" ) == 0 ); + BOOST_TEST( strcmp( ca.get(), "Hot Dog with mustard and relish" ) == 0 ); + BOOST_TEST( strcmp( cap, "Hot Dog with mustard and relish" ) == 0 ); - assert( ca[0] == 'H' ); - assert( ca[30] == 'h' ); + BOOST_TEST( ca[0] == 'H' ); + BOOST_TEST( ca[30] == 'h' ); shared_array ca2 ( ca ); shared_array ca3 ( ca2 ); ca[0] = 'N'; ca[4] = 'd'; - assert( strcmp( ca.get(), "Not dog with mustard and relish" ) == 0 ); - assert( strcmp( ca2.get(), "Not dog with mustard and relish" ) == 0 ); - assert( strcmp( ca3.get(), "Not dog with mustard and relish" ) == 0 ); - assert( ca.use_count() == 3 ); - assert( ca2.use_count() == 3 ); - assert( ca3.use_count() == 3 ); + 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(); - assert( ca.use_count() == 2 ); - assert( ca3.use_count() == 2 ); - assert( ca2.use_count() == 1 ); + BOOST_TEST( ca.use_count() == 2 ); + BOOST_TEST( ca3.use_count() == 2 ); + BOOST_TEST( ca2.use_count() == 1 ); ca.reset(); - assert( ca.get() == 0 ); + BOOST_TEST( ca.get() == 0 ); shared_array ca4; swap( ca3, ca4 ); - assert( ca4.use_count() == 1 ); - assert( strcmp( ca4.get(), "Not dog with mustard and relish" ) == 0 ); - assert( ca3.get() == 0 ); + BOOST_TEST( ca4.use_count() == 1 ); + BOOST_TEST( strcmp( ca4.get(), "Not dog with mustard and relish" ) == 0 ); + BOOST_TEST( ca3.get() == 0 ); #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION set< shared_array > sca; sca.insert(ca4); - assert( sca.find(ca4) != sca.end() ); - assert( sca.find(ca4) == sca.find( shared_array(ca4) ) ); + BOOST_TEST( sca.find(ca4) != sca.end() ); + BOOST_TEST( sca.find(ca4) == sca.find( shared_array(ca4) ) ); #endif // test shared_array with user defined type @@ -221,38 +247,38 @@ int main() { udta[2].value( 333 ); shared_array udta2 ( udta ); - assert( udta[0].value() == 111 ); - assert( udta[1].value() == 222 ); - assert( udta[2].value() == 333 ); - assert( udta2[0].value() == 111 ); - assert( udta2[1].value() == 222 ); - assert( udta2[2].value() == 333 ); + 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(); - assert( udta2.get() == 0 ); - assert( udta.use_count() == 1 ); - assert( udta2.use_count() == 1 ); + BOOST_TEST( udta2.get() == 0 ); + BOOST_TEST( udta.use_count() == 1 ); + BOOST_TEST( udta2.use_count() == 1 ); - assert( UDT_use_count == 4 ); // reality check + BOOST_TEST( UDT_use_count == 4 ); // reality check // test shared_ptr with a user defined type UDT * up = new UDT; shared_ptr sup ( up ); - assert( up == sup.get() ); - assert( sup.use_count() == 1 ); + BOOST_TEST( up == sup.get() ); + BOOST_TEST( sup.use_count() == 1 ); sup->value( 54321 ) ; - assert( sup->value() == 54321 ); - assert( up->value() == 54321 ); + BOOST_TEST( sup->value() == 54321 ); + BOOST_TEST( up->value() == 54321 ); shared_ptr sup2; sup2 = sup; - assert( sup2->value() == 54321 ); - assert( sup.use_count() == 2 ); - assert( sup2.use_count() == 2 ); + BOOST_TEST( sup2->value() == 54321 ); + BOOST_TEST( sup.use_count() == 2 ); + BOOST_TEST( sup2.use_count() == 2 ); sup2 = sup2; - assert( sup2->value() == 54321 ); - assert( sup.use_count() == 2 ); - assert( sup2.use_count() == 2 ); + BOOST_TEST( sup2->value() == 54321 ); + BOOST_TEST( sup.use_count() == 2 ); + BOOST_TEST( sup2.use_count() == 2 ); cout << "OK" << endl; From c41b060618df4e3e51075b4f9690fd721d31cef6 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 24 May 2001 18:43:24 +0000 Subject: [PATCH 024/133] Initial checkin [SVN r10221] --- shared_ptr_example2.cpp | 21 +++++++++++++++++++++ shared_ptr_example2.hpp | 27 +++++++++++++++++++++++++++ shared_ptr_example2_test.cpp | 15 +++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 shared_ptr_example2.cpp create mode 100644 shared_ptr_example2.hpp create mode 100644 shared_ptr_example2_test.cpp diff --git a/shared_ptr_example2.cpp b/shared_ptr_example2.cpp new file mode 100644 index 0000000..eddc806 --- /dev/null +++ b/shared_ptr_example2.cpp @@ -0,0 +1,21 @@ +// 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"; } + +example::~example() {} diff --git a/shared_ptr_example2.hpp b/shared_ptr_example2.hpp new file mode 100644 index 0000000..fea810b --- /dev/null +++ b/shared_ptr_example2.hpp @@ -0,0 +1,27 @@ +// 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(); + 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..1e9886b --- /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; +} \ No newline at end of file From 5fbc553611676fb063334774f134511cec1d1725 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 6 Jul 2001 13:23:07 +0000 Subject: [PATCH 025/133] Reorder shared_ptr code so VC++ 6 member templates work, allowing polymorphic pointers to now work with that compiler (Gary Powell) [SVN r10548] --- include/boost/smart_ptr.hpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp index 442598b..d9c0aa5 100644 --- a/include/boost/smart_ptr.hpp +++ b/include/boost/smart_ptr.hpp @@ -9,6 +9,8 @@ // See http://www.boost.org for most recent version including documentation. // Revision History +// 6 Jul 01 Reorder shared_ptr code so VC++ 6 member templates work, allowing +// polymorphic pointers to now work with that compiler (Gary Powell) // 21 May 01 Require complete type where incomplete type is unsafe. // (suggested by Vladimir Prus) // 21 May 01 operator= fails if operand transitively owned by *this, as in a @@ -136,16 +138,9 @@ template class shared_ptr { catch (...) { checked_delete(p); throw; } } - shared_ptr(const shared_ptr& r) : px(r.px) { ++*(pn = r.pn); } // never throws - ~shared_ptr() { dispose(); } - shared_ptr& operator=(const shared_ptr& r) { - share(r.px,r.pn); - return *this; - } - -#if !defined( BOOST_NO_MEMBER_TEMPLATES ) +#if !defined( BOOST_NO_MEMBER_TEMPLATES ) || defined (BOOST_MSVC6_MEMBER_TEMPLATES) template shared_ptr(const shared_ptr& r) : px(r.px) { // never throws ++*(pn = r.pn); @@ -199,6 +194,15 @@ template class shared_ptr { #endif #endif + // The assignment operator and the copy constructor must come after + // the templated versions for MSVC6 to work. (Gary Powell) + shared_ptr(const shared_ptr& r) : px(r.px) { ++*(pn = r.pn); } // never throws + + shared_ptr& operator=(const shared_ptr& r) { + share(r.px,r.pn); + return *this; + } + void reset(T* p=0) { if ( px == p ) return; // fix: self-assignment safe if (--*pn == 0) { checked_delete(px); } @@ -231,7 +235,7 @@ template class shared_ptr { // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. (Matthew Langston) // Don't split this line into two; that causes problems for some GCC 2.95.2 builds -#if defined(BOOST_NO_MEMBER_TEMPLATES) || !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) +#if ( defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) ) || !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) private: #endif From 65c3f2dc859669732b03f0e93f7c660876642440 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 12 Jul 2001 19:51:53 +0000 Subject: [PATCH 026/133] Add table of contents, improve the FAQ [SVN r10599] --- shared_ptr.htm | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index cdf2b93..33db24b 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -10,6 +10,14 @@

    c++boost.gif (8819 bytes)Class shared_ptr

    +

    Introduction
    +Synopsis

    +Members
    +Example
    +Handle/Body Idiom
    +Frequently Asked Questions
    +Smart Pointer Timings

    +

    Introduction

    Class shared_ptr 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 @@ -33,7 +41,7 @@ object A dangling with a use_count() of 1.

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

    -

    Class shared_ptr Synopsis

    +

    Class shared_ptr Synopsis

    #include <boost/smart_ptr.hpp>
     namespace boost {
     
    @@ -112,7 +120,7 @@ than supplying a full range of comparison operators (<, >, <=, >=).<
     name BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION is defined.

    The current implementation does not supply the member template functions if the macro name BOOST_NO_MEMBER_TEMPLATES is defined.

    -

    Class shared_ptr Members

    +

    Class shared_ptr Members

    shared_ptr element_type

    typedef T element_type;

    Provides the type of the stored pointer.

    @@ -218,19 +226,25 @@ 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.

    -

    FAQ

    +

    Frequently Asked Questions

    Q. Why doesn't shared_ptr have template parameters supplying traits or policies to allow extensive user customization?
    A. Parameterization discourages users.  Shared_ptr is carefully crafted to meet common needs without extensive parameterization. Someday a highly configurable smart pointer may be invented that is also very easy to use and very hard to misuse.  Until then, shared_ptr is the -smart pointer of choice for a wide range of applications.

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

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


    -

    Revised 24 May, 2001 +

    Revised 12 July, 2001

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright From aea7d0c9c8ffe5763148bc30ea1ed7ed984505a3 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 13 Jul 2001 14:07:08 +0000 Subject: [PATCH 027/133] Add FAQ why use_count()? [SVN r10604] --- shared_ptr.htm | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index 33db24b..3f6c7df 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -227,24 +227,28 @@ implementation.   The instantiation of member functions which require a complete type occurs in the shared_ptr_example2.cpp implementation file.

    Frequently Asked Questions

    -

    Q. Why doesn't shared_ptr have template parameters supplying +

    Q. Why doesn't shared_ptr have template parameters supplying traits or policies to allow extensive user customization?
    -A. Parameterization discourages users.  Shared_ptr is +A. Parameterization discourages users.  Shared_ptr is carefully crafted to meet common needs without extensive parameterization. Someday a highly configurable smart pointer may be invented that is also very easy to use and very hard to misuse.  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. Why doesn't shared_ptr use a linked list implementation?
    -A. A linked list implementation does not offer enough advantages to +

    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.

    -

    Q. Why don't shared_ptr (and the other Boost smart pointers) +

    Q. Why don't shared_ptr (and the other Boost smart pointers) supply an automatic conversion to T*?
    -A. Automatic conversion is believed to be too error prone.

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


    -

    Revised 12 July, 2001 +

    Revised 13 July, 2001

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright From c5846378ab2789f82510bbc80ac5a1a8dacddb6e Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 13 Jul 2001 16:32:34 +0000 Subject: [PATCH 028/133] More FAQ entries added. [SVN r10605] --- shared_ptr.htm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/shared_ptr.htm b/shared_ptr.htm index 3f6c7df..c9fe1e6 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -247,6 +247,14 @@ supply an automatic conversion to T*?
    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 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 (your pet feature here)?
    +A. Because (your pet feature here) would mandate a reference counted (or a link-list, or ...) implementation. This is not the intent. +[Provided by Peter Dimov]
    +


    Revised 13 July, 2001

    From a93dfc1837480fab88c646b7d4f5d403ba26188a Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Sun, 19 Aug 2001 15:08:33 +0000 Subject: [PATCH 029/133] Fix broken hyperlink [SVN r10896] --- smarttests.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smarttests.htm b/smarttests.htm index f78b618..ad0fbb1 100644 --- a/smarttests.htm +++ b/smarttests.htm @@ -530,7 +530,7 @@ Pointers Timings spreads its information as in the case of linked pointer.
    -

    Revised 27 Jul 2000 +

    Revised 17 Aug 2001

    İ Copyright Gavin Collings 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all From 1a9b1dd123abc92a0ba534f8e457bd94045a3f74 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Mon, 1 Oct 2001 15:54:23 +0000 Subject: [PATCH 030/133] 1.25.0 Final runup [SVN r11315] --- smarttests.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smarttests.htm b/smarttests.htm index ad0fbb1..dcd8fda 100644 --- a/smarttests.htm +++ b/smarttests.htm @@ -530,7 +530,7 @@ Pointers Timings spreads its information as in the case of linked pointer.


    -

    Revised 17 Aug 2001 +

    Revised 19 Aug 2001

    İ Copyright Gavin Collings 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all From 11ec5153783df16d216450fbdc8edd8bd0862d7f Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 11 Jan 2002 16:15:09 +0000 Subject: [PATCH 031/133] Fix broken link [SVN r12285] --- shared_ptr.htm | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index c9fe1e6..2108b43 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -2,21 +2,22 @@ shared_ptr - + -

    c++boost.gif (8819 bytes)Class +

    +c++boost.gif (8819 bytes)Class shared_ptr

    Introduction
    Synopsis

    Members
    Example
    Handle/Body Idiom
    -Frequently Asked Questions
    -Smart Pointer Timings

    +Frequently Asked Questions
    +Smart Pointer Timings

    Introduction

    Class shared_ptr stores a pointer to a dynamically allocated object. (Dynamically allocated objects are allocated with the C++ new @@ -256,7 +257,7 @@ had to meet stringent complexity requirements.

    [Provided by Peter Dimov]


    -

    Revised 13 July, 2001 +

    Revised 11 January, 2002

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright @@ -266,4 +267,4 @@ any purpose.

    - + \ No newline at end of file From 4f964ce6ada8f1585828f1320511acc9892b94fa Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 11 Jan 2002 20:20:07 +0000 Subject: [PATCH 032/133] Add FAQ: why no release() [SVN r12286] --- shared_ptr.htm | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index 2108b43..4913f65 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -252,9 +252,23 @@ complex project that turned out to have cyclic-dependencies.

    A. Because complexity 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.
    +
    +

    [Provided by Peter Dimov]

    Q. Why doesn't shared_ptr provide (your pet feature here)?
    A. Because (your pet feature here) would mandate a reference counted (or a link-list, or ...) implementation. This is not the intent. -[Provided by Peter Dimov]
    +[Provided by Peter Dimov]

    +



    Revised 11 January, 2002 From b104e9ae7843821f98efdbbe1ae0ea903240fb58 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 17 Jan 2002 12:46:45 +0000 Subject: [PATCH 033/133] smart_ptr.hpp less<> fixed, partial specialization enabled on Sun 5.3 [SVN r12334] --- include/boost/smart_ptr.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp index d9c0aa5..dbcb787 100644 --- a/include/boost/smart_ptr.hpp +++ b/include/boost/smart_ptr.hpp @@ -377,7 +377,7 @@ template { bool operator()(const boost::shared_ptr& a, const boost::shared_ptr& b) const - { return less()(a.get(),b.get()); } + { return std::less()(a.get(),b.get()); } }; template @@ -386,7 +386,7 @@ template { bool operator()(const boost::shared_array& a, const boost::shared_array& b) const - { return less()(a.get(),b.get()); } + { return std::less()(a.get(),b.get()); } }; } // namespace std From f255439ece0687eb61b8bcae576faf9b2521912f Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Sat, 19 Jan 2002 15:54:28 +0000 Subject: [PATCH 034/133] add eof newline [SVN r12358] --- scoped_ptr_example_test.cpp | 2 +- shared_ptr_example2_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scoped_ptr_example_test.cpp b/scoped_ptr_example_test.cpp index 3629ec8..1b77af2 100644 --- a/scoped_ptr_example_test.cpp +++ b/scoped_ptr_example_test.cpp @@ -7,4 +7,4 @@ int main() example my_example; my_example.do_something(); return 0; -} \ No newline at end of file +} diff --git a/shared_ptr_example2_test.cpp b/shared_ptr_example2_test.cpp index 1e9886b..3a2cf53 100644 --- a/shared_ptr_example2_test.cpp +++ b/shared_ptr_example2_test.cpp @@ -12,4 +12,4 @@ int main() c = a; c.do_something(); return 0; -} \ No newline at end of file +} From 09c14760632986e4068a059411cae9c89cb84f46 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 22 Jan 2002 13:38:52 +0000 Subject: [PATCH 035/133] Smart pointer enhancements, initial commit [SVN r12439] --- include/boost/detail/atomic_count.hpp | 122 +++++++++ include/boost/detail/atomic_count_linux.hpp | 64 +++++ .../boost/detail/atomic_count_pthreads.hpp | 99 +++++++ include/boost/detail/atomic_count_win32.hpp | 68 +++++ include/boost/detail/shared_array_nmt.hpp | 135 ++++++++++ include/boost/detail/shared_count.hpp | 250 ++++++++++++++++++ include/boost/detail/shared_ptr_nmt.hpp | 165 ++++++++++++ include/boost/scoped_array.hpp | 87 ++++++ include/boost/scoped_ptr.hpp | 90 +++++++ include/boost/shared_array.hpp | 136 ++++++++++ include/boost/shared_ptr.hpp | 246 +++++++++++++++++ include/boost/weak_ptr.hpp | 175 ++++++++++++ 12 files changed, 1637 insertions(+) create mode 100644 include/boost/detail/atomic_count.hpp create mode 100644 include/boost/detail/atomic_count_linux.hpp create mode 100644 include/boost/detail/atomic_count_pthreads.hpp create mode 100644 include/boost/detail/atomic_count_win32.hpp create mode 100644 include/boost/detail/shared_array_nmt.hpp create mode 100644 include/boost/detail/shared_count.hpp create mode 100644 include/boost/detail/shared_ptr_nmt.hpp create mode 100644 include/boost/scoped_array.hpp create mode 100644 include/boost/scoped_ptr.hpp create mode 100644 include/boost/shared_array.hpp create mode 100644 include/boost/shared_ptr.hpp create mode 100644 include/boost/weak_ptr.hpp diff --git a/include/boost/detail/atomic_count.hpp b/include/boost/detail/atomic_count.hpp new file mode 100644 index 0000000..0a22e64 --- /dev/null +++ b/include/boost/detail/atomic_count.hpp @@ -0,0 +1,122 @@ +#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... +// + + +#include + +#ifndef BOOST_HAS_THREADS + +namespace boost +{ + +namespace detail +{ + +typedef long atomic_count; + +} + +} + +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) + +#include "atomic_count_win32.hpp" + +#elif defined(linux) || defined(__linux) || defined(__linux__) + +#include "atomic_count_linux.hpp" + +#elif defined(BOOST_HAS_PTHREADS) + +#include "atomic_count_pthreads.hpp" + +#else + +// #warning Unrecognized platform, detail::atomic_count will not be thread safe + +namespace boost +{ + +namespace detail +{ + +typedef long atomic_counter; + +} + +} + +#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..8fd5346 --- /dev/null +++ b/include/boost/detail/atomic_count_linux.hpp @@ -0,0 +1,64 @@ +#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. +// + +// +// On Linux, atomic.h is usually located in /usr/include/asm +// + +#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..eb1dd97 --- /dev/null +++ b/include/boost/detail/atomic_count_pthreads.hpp @@ -0,0 +1,99 @@ +#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. +// +// Define a macro so that users can detect the situation and optimize. +// + +#define BOOST_ATOMIC_COUNT_USES_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..163a26d --- /dev/null +++ b/include/boost/detail/atomic_count_win32.hpp @@ -0,0 +1,68 @@ +#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. +// + +namespace boost +{ + +namespace detail +{ + +// Avoid #including + +namespace win32 +{ +extern "C" __declspec(dllimport) long __stdcall InterlockedIncrement(long volatile *); +extern "C" __declspec(dllimport) long __stdcall InterlockedDecrement(long volatile *); +} + +class atomic_count +{ +public: + + explicit atomic_count(long v): value_(v) + { + } + + long operator++() + { + return win32::InterlockedIncrement(&value_); + } + + long operator--() + { + return win32::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/shared_array_nmt.hpp b/include/boost/detail/shared_array_nmt.hpp new file mode 100644 index 0000000..e5137a3 --- /dev/null +++ b/include/boost/detail/shared_array_nmt.hpp @@ -0,0 +1,135 @@ +#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 for most recent version including 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) + { + 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..46ceaf5 --- /dev/null +++ b/include/boost/detail/shared_count.hpp @@ -0,0 +1,250 @@ +#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 + +namespace boost +{ + +namespace detail +{ + +class counted_base +{ +public: + + typedef atomic_count count_type; + + 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() + { + } + + virtual void dispose() + { + } + + void add_ref() + { + ++use_count_; + ++weak_count_; + } + + void release() + { + if(--use_count_ == 0) + { + dispose(); + } + + if(--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() + { + ++weak_count_; + } + + void weak_release() + { + if(--weak_count_ == 0) + { + self_deleter_(this); + } + } + + long use_count() const + { + return use_count_; + } + +private: + + counted_base(counted_base const &); + counted_base & operator= (counted_base const &); + + static void self_delete(counted_base * p) + { + delete p; + } + + count_type use_count_; + count_type weak_count_; + + void (*self_deleter_) (counted_base *); +}; + +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: + + 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() + { + del(ptr); + } +}; + + +class shared_count +{ +private: + + counted_base * pi_; + + friend class weak_count; + +public: + + template shared_count(P p, D d): pi_(0) + { + try + { + pi_ = new counted_base_impl(p, d, 1, 1); + } + catch(...) + { + d(p); // delete p + throw; + } + } + + ~shared_count() // nothrow + { + pi_->release(); + } + + shared_count(shared_count const & r): pi_(r.pi_) // nothrow + { + pi_->add_ref(); + } + + 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; + } +}; + +class weak_count +{ +private: + + counted_base * pi_; + +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(); + } +}; + +} // 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..8b268a2 --- /dev/null +++ b/include/boost/detail/shared_ptr_nmt.hpp @@ -0,0 +1,165 @@ +#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 for most recent version including 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) + { + 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/scoped_array.hpp b/include/boost/scoped_array.hpp new file mode 100644 index 0000000..3fcce8d --- /dev/null +++ b/include/boost/scoped_array.hpp @@ -0,0 +1,87 @@ +#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 for most recent version including documentation. + +#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() + { + typedef char type_must_be_complete[sizeof(T)]; + delete [] ptr; + } + + void reset( T* p = 0 ) + { + typedef char type_must_be_complete[sizeof(T)]; + + if ( ptr != p ) + { + 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 & rhs) + { + T * tmp = rhs.ptr; + rhs.ptr = ptr; + ptr = tmp; + } + +}; + +template inline void swap(scoped_array & a, scoped_array & b) +{ + 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..b920a72 --- /dev/null +++ b/include/boost/scoped_ptr.hpp @@ -0,0 +1,90 @@ +#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 for most recent version including documentation. + +#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() + { + typedef char type_must_be_complete[sizeof(T)]; + delete ptr; + } + + void reset( T* p = 0 ) + { + typedef char type_must_be_complete[sizeof(T)]; + + if ( ptr != p ) + { + 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 & rhs) + { + T * tmp = rhs.ptr; + rhs.ptr = ptr; + ptr = tmp; + } +}; + +template inline void swap(scoped_ptr & a, scoped_ptr & b) +{ + 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..85741b2 --- /dev/null +++ b/include/boost/shared_array.hpp @@ -0,0 +1,136 @@ +#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 for most recent version including documentation. +// + +#include // for broken compiler workarounds + +#if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(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) + { + this_type(p).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; + } + + long use_count() const // never throws + { + return pn.use_count(); + } + + bool unique() const // never throws + { + return pn.unique(); + } + + 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) +{ + 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 // #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC_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..996a1b5 --- /dev/null +++ b/include/boost/shared_ptr.hpp @@ -0,0 +1,246 @@ +#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 for most recent version including documentation. +// + +#include // for broken compiler workarounds + +#if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) +#include +#else + +#include +#include + +#include + +#include // for std::auto_ptr +#include // for std::swap +#include // for std::less + +#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 {}; + +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 shared_ptr +{ +private: + + // Borland 5.5.1 specific workarounds + typedef checked_deleter deleter; + typedef shared_ptr this_type; + +public: + + typedef T element_type; + + explicit shared_ptr(T * p = 0): px(p), pn(p, deleter()) + { + } + + // + // Requirements: D's copy constructor must not throw + // + // shared_ptr will release p by calling d(p) + // + + template shared_ptr(T * p, D d): px(p), pn(p, d) + { + } + +// generated copy constructor, assignment, destructor are fine + + template + shared_ptr(shared_ptr const & r): px(r.px), pn(r.pn) // 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(static_cast(0), deleter()); + } + } + +#ifndef BOOST_NO_AUTO_PTR + + template + explicit shared_ptr(std::auto_ptr & r): px(r.get()), pn(r.release(), checked_deleter()) + { + } + +#endif + + template + shared_ptr & operator=(shared_ptr const & r) // nothrow? + { + px = r.px; + pn = r.pn; // shared_count::op= doesn't throw + return *this; + } + +#ifndef BOOST_NO_AUTO_PTR + + template + shared_ptr & operator=(std::auto_ptr & r) + { + this_type(r).swap(*this); + return *this; + } + +#endif + + void reset(T * p = 0) + { + this_type(p).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; + } + + long use_count() const // never throws + { + return pn.use_count(); + } + + bool unique() const // never throws + { + return pn.unique(); + } + + 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(); +} + +template inline bool operator<(shared_ptr const & a, shared_ptr const & b) +{ + return std::less()(a.get(), b.get()); +} + +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 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 + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif // #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC_MEMBER_TEMPLATES) + +#endif // #ifndef BOOST_SHARED_PTR_HPP_INCLUDED diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp new file mode 100644 index 0000000..87231c3 --- /dev/null +++ b/include/boost/weak_ptr.hpp @@ -0,0 +1,175 @@ +#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 for most recent version including documentation. +// + +#include + +#include // for broken compiler workarounds +#include + +#include + +#include // for std::swap +#include // for std::less + +#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(shared_ptr const & r): px(r.px), pn(r.pn) // never throws + { + } + + template + weak_ptr(weak_ptr const & r, detail::static_cast_tag): px(static_cast(r.px)), pn(r.pn) + { + } + + template + weak_ptr(weak_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::weak_count(); + } + } + + template + weak_ptr & operator=(weak_ptr const & r) // nothrow? + { + px = r.px; + pn = r.pn; + return *this; + } + + void reset() + { + this_type().swap(*this); + } + + long use_count() const // never throws + { + return pn.use_count(); + } + + T * get() const // never throws + { + return use_count() == 0? 0: px; + } + + typename detail::shared_ptr_traits::reference operator* () const // never throws + { + T * p = get(); + + BOOST_ASSERT(p != 0); + return *p; + } + + T * operator-> () const // never throws + { + T * p = get(); + + BOOST_ASSERT(p != 0); + return p; + } + + void swap(weak_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 weak_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(); +} + +template inline bool operator<(weak_ptr const & a, weak_ptr const & b) +{ + return std::less()(a.get(), b.get()); +} + +template weak_ptr shared_static_cast(weak_ptr const & r) +{ + return weak_ptr(r, detail::static_cast_tag()); +} + +template weak_ptr shared_dynamic_cast(weak_ptr const & r) +{ + return weak_ptr(r, detail::dynamic_cast_tag()); +} + +template void swap(weak_ptr & a, weak_ptr & b) +{ + a.swap(b); +} + +// get_pointer() enables boost::mem_fn to recognize weak_ptr + +template inline T * get_pointer(weak_ptr const & p) +{ + return p.get(); +} + +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif // #ifndef BOOST_WEAK_PTR_HPP_INCLUDED From 5d564a2f01f0caf9e11261b988dbef1abaf91392 Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Thu, 24 Jan 2002 19:16:12 +0000 Subject: [PATCH 036/133] Add a self-assignment assert to reset(). Also add an overload of reset to allow resetting to a new pointer with a new deletion function. [SVN r12491] --- include/boost/detail/shared_array_nmt.hpp | 1 + include/boost/detail/shared_ptr_nmt.hpp | 1 + include/boost/shared_array.hpp | 1 + include/boost/shared_ptr.hpp | 8 +++++++- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/boost/detail/shared_array_nmt.hpp b/include/boost/detail/shared_array_nmt.hpp index e5137a3..570af13 100644 --- a/include/boost/detail/shared_array_nmt.hpp +++ b/include/boost/detail/shared_array_nmt.hpp @@ -72,6 +72,7 @@ public: void reset(T * p = 0) { + BOOST_ASSERT(p == 0 || p != px); shared_array(p).swap(*this); } diff --git a/include/boost/detail/shared_ptr_nmt.hpp b/include/boost/detail/shared_ptr_nmt.hpp index 8b268a2..5364e77 100644 --- a/include/boost/detail/shared_ptr_nmt.hpp +++ b/include/boost/detail/shared_ptr_nmt.hpp @@ -91,6 +91,7 @@ public: void reset(T * p = 0) { + BOOST_ASSERT(p == 0 || p != px); shared_ptr(p).swap(*this); } diff --git a/include/boost/shared_array.hpp b/include/boost/shared_array.hpp index 85741b2..5098dee 100644 --- a/include/boost/shared_array.hpp +++ b/include/boost/shared_array.hpp @@ -71,6 +71,7 @@ public: void reset(T * p = 0) { + BOOST_ASSERT(p == 0 || p != px); this_type(p).swap(*this); } diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index 996a1b5..db75b9e 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -33,7 +33,7 @@ #ifdef BOOST_MSVC // moved here to work around VC++ compiler crash # pragma warning(push) # pragma warning(disable:4284) // odd return type for operator-> -#endif +#endif namespace boost { @@ -144,9 +144,15 @@ public: 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); + } + typename detail::shared_ptr_traits::reference operator* () const // never throws { BOOST_ASSERT(px != 0); From 58c5711b47153d50a914c5e86090517b9c35e83f Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 25 Jan 2002 13:54:30 +0000 Subject: [PATCH 037/133] Added tests for the new smart pointers. [SVN r12500] --- shared_ptr_test.cpp | 157 +++++++++++++++++++++++ smart_ptr_test2.cpp | 295 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 452 insertions(+) create mode 100644 shared_ptr_test.cpp create mode 100644 smart_ptr_test2.cpp diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp new file mode 100644 index 0000000..3dd5e98 --- /dev/null +++ b/shared_ptr_test.cpp @@ -0,0 +1,157 @@ +#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_test.cpp - a test for shared_ptr.hpp and weak_ptr.hpp +// +// Copyright (c) 2001 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"; + } + + virtual ~X() + { + --cnt; + std::cout << "X(" << this << ")::~X()\n"; + } + +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"; + } + +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"; +} + +int test_main(int, char * []) +{ + using namespace boost; + + { + shared_ptr p(new Y); + shared_ptr p2(new X); + + shared_ptr p3 = shared_dynamic_cast(p); + shared_ptr p4 = shared_dynamic_cast(p2); + + BOOST_TEST(p.use_count() == 2); + BOOST_TEST(p2.use_count() == 1); + BOOST_TEST(p3.use_count() == 2); + BOOST_TEST(p4.use_count() == 1); + + shared_ptr p5(p); + + std::cout << "--\n"; + + p.reset(); + p2.reset(); + p3.reset(); + p4.reset(); + + std::cout << "--\n"; + + BOOST_TEST(p5.use_count() == 1); + + weak_ptr wp1; + + BOOST_TEST(wp1.use_count() == 0); + BOOST_TEST(wp1.get() == 0); + + weak_ptr wp2 = shared_static_cast(p5); + + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(wp2.get() != 0); + + weak_ptr wp3 = shared_dynamic_cast(wp2); + + BOOST_TEST(wp3.use_count() == 1); + BOOST_TEST(wp3.get() != 0); + BOOST_TEST(wp2 == wp3); + + wp1 = wp2; + + BOOST_TEST(wp1.use_count() == 1); + BOOST_TEST(wp1.get() != 0); + BOOST_TEST(wp1 == wp2); + + 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); + + shared_ptr p6(get_object(), release_object); + } + + BOOST_TEST(cnt == 0); + + return 0; +} diff --git a/smart_ptr_test2.cpp b/smart_ptr_test2.cpp new file mode 100644 index 0000000..4ea305e --- /dev/null +++ b/smart_ptr_test2.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" << endl; + } + long value() const { return value_; } + void value( long v ) { value_ = v;; } + }; // UDT + +// tests on incomplete types -----------------------------------------------// + +// Certain smart pointer operations are specified to work on incomplete types, +// and some uses depend upon this feature. These tests verify compilation +// only - the functions aren't actually invoked. + +class Incomplete; + +Incomplete * check_incomplete( scoped_ptr& incomplete ) +{ + return incomplete.get(); +} + +Incomplete * check_incomplete( shared_ptr& incomplete, + shared_ptr& i2 ) +{ + incomplete.swap(i2); + cout << incomplete.use_count() << " " << incomplete.unique() << endl; + return incomplete.get(); +} +// main --------------------------------------------------------------------// + +// This isn't a very systematic test; it just hits some of the basics. + +int test_main( int, char ** ) { + + BOOST_TEST( UDT_use_count == 0 ); // reality check + + // test scoped_ptr with a built-in type + long * lp = new long; + scoped_ptr 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" << endl; + + new char[12345]; // deliberate memory leak to verify leaks detected + + return 0; + } // main + From a8efe20862a99d8c59953dcd49ca87bc574aae4c Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 25 Jan 2002 16:10:26 +0000 Subject: [PATCH 038/133] Comments added. [SVN r12510] --- include/boost/detail/shared_count.hpp | 31 ++++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 46ceaf5..cf8f8ee 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -30,26 +30,37 @@ public: typedef atomic_count count_type; + // 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() + virtual ~counted_base() // nothrow { } - virtual void dispose() + // 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() + void add_ref() // nothrow { ++use_count_; ++weak_count_; } - void release() + void release() // nothrow { if(--use_count_ == 0) { @@ -64,12 +75,12 @@ public: } } - void weak_add_ref() + void weak_add_ref() // nothrow { ++weak_count_; } - void weak_release() + void weak_release() // nothrow { if(--weak_count_ == 0) { @@ -77,7 +88,7 @@ public: } } - long use_count() const + long use_count() const // nothrow { return use_count_; } @@ -92,6 +103,8 @@ private: delete p; } + // inv: use_count_ <= weak_count_ + count_type use_count_; count_type weak_count_; @@ -110,12 +123,14 @@ private: 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() + virtual void dispose() // nothrow { del(ptr); } From 4fdc84f29eeb7b19e1cb731d55f6ab29cb458350 Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Thu, 31 Jan 2002 06:52:58 +0000 Subject: [PATCH 039/133] Make the non-threads version work. [SVN r12597] --- include/boost/detail/atomic_count.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/detail/atomic_count.hpp b/include/boost/detail/atomic_count.hpp index 0a22e64..0f33ac4 100644 --- a/include/boost/detail/atomic_count.hpp +++ b/include/boost/detail/atomic_count.hpp @@ -111,7 +111,7 @@ namespace boost namespace detail { -typedef long atomic_counter; +typedef long atomic_count; } From 39c10f739d8a809a1d86b3e0bc8174fd00040b0d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 1 Feb 2002 18:40:35 +0000 Subject: [PATCH 040/133] added an auto_ptr & constructor to shared_count [SVN r12623] --- include/boost/detail/shared_count.hpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index cf8f8ee..8756294 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -16,6 +16,13 @@ // warranty, and with no claim as to its suitability for any purpose. // +#include + +#ifndef BOOST_NO_AUTO_PTR +# include +#endif + +#include #include namespace boost @@ -160,6 +167,18 @@ public: } } +#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(); From 8b5b780c2c4f6251370d3cac8cc721ae5b8b18d5 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 1 Feb 2002 19:34:31 +0000 Subject: [PATCH 041/133] better weak_ptr coverage [SVN r12624] --- shared_ptr_test.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp index 3dd5e98..7387cc8 100644 --- a/shared_ptr_test.cpp +++ b/shared_ptr_test.cpp @@ -131,6 +131,11 @@ int test_main(int, char * []) BOOST_TEST(wp3.get() != 0); BOOST_TEST(wp2 == wp3); + weak_ptr wp4(wp3); + + wp1 = p2; + wp1 = p4; + wp1 = wp3; wp1 = wp2; BOOST_TEST(wp1.use_count() == 1); From b224270cc0d70243af4455b62867c781c6d3e72f Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 2 Feb 2002 16:18:04 +0000 Subject: [PATCH 042/133] auto_ptr& constructor now has no effects when exception is thrown [SVN r12643] --- include/boost/shared_ptr.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index db75b9e..eb4d662 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -117,7 +117,7 @@ public: #ifndef BOOST_NO_AUTO_PTR template - explicit shared_ptr(std::auto_ptr & r): px(r.get()), pn(r.release(), checked_deleter()) + explicit shared_ptr(std::auto_ptr & r): px(r.get()), pn(r) { } From d3c76575f945d225d690d1134005a4594aa7dccd Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 2 Feb 2002 16:19:45 +0000 Subject: [PATCH 043/133] templated copy constructor added. [SVN r12644] --- include/boost/weak_ptr.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index 87231c3..d73c5f3 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -49,6 +49,11 @@ public: // 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 { From 1a7cd887e4ee658f763d88590a2a05b9ad76ac7b Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Sat, 2 Feb 2002 18:36:12 +0000 Subject: [PATCH 044/133] New smart pointer documentation. Related clean-up of the smart pointer library. Changing includes to include the new individual smart pointer headers. Replacing old smart pointer library with an include of the new smart pointer headers. Simplify ifdefs that involve the member templates macros now that BOOST_MSVC6_MEMBER_TEMPLATES is also guaranteed to bet set for platforms that have full member templates. [SVN r12647] --- compatibility.htm | 105 +++++++ include/boost/scoped_array.hpp | 20 +- include/boost/scoped_ptr.hpp | 26 +- include/boost/shared_array.hpp | 27 +- include/boost/shared_ptr.hpp | 52 ++-- include/boost/smart_ptr.hpp | 405 +------------------------- include/boost/weak_ptr.hpp | 36 +-- index.htm | 31 +- scoped_array.htm | 191 ++++++++----- scoped_ptr.htm | 262 ++++++++++------- scoped_ptr_example.hpp | 2 +- shared_array.htm | 351 +++++++++++++---------- shared_ptr.htm | 506 +++++++++++++++++++-------------- shared_ptr_example.cpp | 2 +- shared_ptr_example2.cpp | 2 - shared_ptr_example2.hpp | 3 +- smart_ptr.htm | 196 ++++++++----- smart_ptr_test.cpp | 22 +- smart_ptr_test2.cpp | 295 ------------------- smarttests.htm | 25 +- weak_ptr.htm | 233 +++++++++++++++ 21 files changed, 1367 insertions(+), 1425 deletions(-) create mode 100644 compatibility.htm delete mode 100644 smart_ptr_test2.cpp create mode 100644 weak_ptr.htm diff --git a/compatibility.htm b/compatibility.htm new file mode 100644 index 0000000..65acfd7 --- /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

    + +
      + +
    • The smart pointer class templates now each have their own header file. +For compatibility, the +<boost/smart_ptr.hpp> +header now includes the headers for the four classic smart pointer class templates.
    • + +
    • The weak_ptr template was added.
    • + +
    • The new shared_ptr and shared_array relax the requirement that the pointed-to object's +destructor must be visible when instantiating the shared_ptr destructor. +This makes it easier to have shared_ptr members in classes without explicit destructors.
    • + +
    • A custom deallocator can be passed in when creating a shared_ptr or shared_array.
    • + +
    • shared_static_cast and shared_dynamic_cast function templates are +provided which work for shared_ptr and weak_ptr as static_cast and +dynamic_cast do for pointers.
    • + +
    • The self-assignment misfeature has been removed from shared_ptr::reset, +although it is still present in scoped_ptr, and in std::auto_ptr. +Calling reset with a pointer to the object that's already owned by the +shared_ptr results in undefined behavior +(an assertion, or eventually a double-delete if assertions are off).
    • + +
    • The BOOST_SMART_PTR_CONVERSION feature has been removed.
    • + +
    • shared_ptr<void> is now allowed.
    • + +
    + +

    Features That Improve Robustness

    + +
      + +
    • The manipulation of use counts is now thread safe on Windows, Linux, and platforms +that support pthreads. See the +<boost/detail/atomic_count.hpp> +file for details
    • + +
    • The new shared_ptr will always delete the object using the pointer it was originally constructed with. +This prevents subtle problems that could happen if the last shared_ptr was a pointer to a sub-object +of a class that did not have a virtual destructor.
    • + +
    + +

    Implementation Details

    + +
      + +
    • Some bugs in the assignment operator implementations and in reset +have been fixed by using the "copy and swap" idiom.
    • + +
    • Assertions have been added to check preconditions of various functions; +however, since these use the new +<boost/assert.hpp> +header, the assertions are disabled by default.
    • + +
    • The partial specialization of std::less has been replaced by operator< +overloads which accomplish the same thing without relying on undefined behavior.
    • + +
    • The incorrect overload of std::swap has been replaced by boost::swap, which +has many of the same advantages for generic programming but does not violate the C++ standard.
    • + +
    + +
    + +

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

    Smart pointer library

    -

    The header smart_ptr.hpp provides four smart pointer classes.  Smart -pointers ease the management of memory dynamically allocated with C++ new -expressions. +

    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 14 Mar 2001 -

    + +

    Revised 1 February 2002.

    diff --git a/scoped_array.htm b/scoped_array.htm index 518b4cb..4df98a9 100644 --- a/scoped_array.htm +++ b/scoped_array.htm @@ -1,101 +1,144 @@ + + + scoped_array - - -

    c++boost.gif (8819 bytes)Class -scoped_array

    -

    Class scoped_array 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 scoped_array::reset().

    -

    Class scoped_array is a simple solution for simple -needs. It supplies a basic "resource acquisition is +

    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.  By -being noncopyable, it is +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 + +

    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.

    -

    Class scoped_array cannot correctly hold a pointer to a -single object.  See scoped_ptr + +

    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 C++ Standard Library vector is a heavier duty alternative to a scoped_array.

    -

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

    -

    Class scoped_array Synopsis

    -
    #include <boost/smart_ptr.hpp>
    -namespace boost {
     
    -template<typename T> class scoped_array : noncopyable {
    +

    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.

    - public: - typedef T element_type; +

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

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

    Synopsis

    - void reset( T* p=0 ); +
    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
     
    -   T& operator[](std::size_t i) const;  // never throws
    -   T* get() const;  // never throws
    -   };
     }
    -

    Class scoped_array Members

    -

    scoped_array element_type

    + +

    Members

    + +

    +element_type

    typedef T element_type;

    Provides the type of the stored pointer.

    -

    scoped_array 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 Common Requirements.

    -

    scoped_array destructor

    -
    ~scoped_array();
    -

    Deletes the array pointed to by the stored pointer.  Note that in C++ delete[] -on a pointer with a value of 0 is harmless.

    -

    Does not throw exceptions.

    -

    scoped_array reset

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

    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.

    -

    Does not throw exceptions.

    -

    scoped_array operator[]

    -

    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 get()==0, -or if i is less than 0 or is greater or equal to the number of elements +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.

    -

    scoped_array get

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

    T is not required be a complete type.  -See Common Requirements.

    -

    Returns the stored pointer.

    -

    Class scoped_array example

    -

    [To be supplied. In the meantime, see smart_ptr_test.cpp.]

    + +

    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  24 May, 2001 -

    -

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, -modify, sell and distribute this document is granted provided this copyright -notice appears in all copies. This document is provided "as is" -without express or implied warranty, and with no claim as to its suitability for -any purpose.

    + +

    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 index 652d1bb..ec0057d 100644 --- a/scoped_ptr.htm +++ b/scoped_ptr.htm @@ -1,152 +1,216 @@ + + + scoped_ptr - - -

    c++boost.gif (8819 bytes)Class -scoped_ptr

    -

    Class scoped_ptr 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 scoped_ptr::reset().  -See example.

    -

    Class scoped_ptr is a simple solution for simple -needs.  It supplies a basic "resource acquisition is +

    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.  +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 +safer than shared_ptr or std::auto_ptr for pointers which should not be copied.

    -

    Because scoped_ptr is so simple, in its usual implementation + +

    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.  (Because of the "complete type" -requirement for delete and reset members, they may have one additional function -call overhead in certain idioms.  See Handle/Body -Idiom.)   

    -

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

    -

    Class scoped_ptr cannot correctly hold a pointer to a -dynamically allocated array.  See scoped_array +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 is a template parameterized on T, the type of the object -pointed to.   T must meet the smart pointer common -requirements.

    -

    Class scoped_ptr Synopsis

    -
    #include <boost/smart_ptr.hpp>
    -namespace boost {
     
    -template<typename T> class scoped_ptr : noncopyable {
    +

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

    - public: - typedef T element_type; +

    Synopsis

    - explicit scoped_ptr( T* p=0 ); // never throws - ~scoped_ptr(); +
    namespace boost {
     
    -   void reset( T* p=0 );
    +  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
     
    -   T& operator*() const;  // never throws
    -   T* operator->() const;  // never throws
    -   T* get() const;  // never throws
    -   };
     }
    -

    Class scoped_ptr Members

    -

    scoped_ptr element_type

    + +

    Members

    + +

    element_type

    typedef T element_type;

    Provides the type of the stored pointer.

    -

    scoped_ptr constructors

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

    T is not required be a complete type.  -See Common Requirements.

    -

    Constructs a scoped_ptr, storing a copy of p, which must -have been allocated via a C++ new expression or be 0.

    -

    scoped_ptr destructor

    -
    ~scoped_ptr();
    -

    Deletes the object pointed to by the stored pointer.  Note that in C++, delete -on a pointer with a value of 0 is harmless.

    -

    Does not throw exceptions.

    -

    scoped_ptr reset

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

    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.

    -

    Does not throw exceptions.

    -

    scoped_ptr operator*

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

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

    -

    scoped_ptr operator-> and get

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

    T is not required by get() be a complete type.  See Common Requirements.

    -

    Both return the stored pointer.

    -

    Class scoped_ptr examples

    -
    #include <iostream>
    -#include <boost/smart_ptr.h>
    +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.

    -struct Shoe { ~Shoe(){ std::cout << "Buckle my shoe" << std::endl; } }; +

    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() {
    +void main()
    +{
         boost::scoped_ptr<Shoe> x(new Shoe);
         MyClass my_instance;
    -    std::cout << my_instance.add_one() << std::endl;
    -    std::cout << my_instance.add_one() << std::endl;
    -    }
    -

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

    + 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 actually 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 - you are signaling intent.

    -

    It has been suggested that boost::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.

    + +

    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. The +instantiation of member functions which require a complete type occurs in +the scoped_ptr_example.cpp implementation file.

    -

    FAQ

    + +

    Frequently Asked Questions

    +

    Q. Why doesn't scoped_ptr have a release() member?
    -A. Because the whole point of scoped_ptr is to signal intent not -to transfer ownership.  Use std::auto_ptr if ownership transfer is +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 24 May 2001

    -

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, -modify, sell and distribute this document is granted provided this copyright -notice appears in all copies. This document is provided "as is" -without express or implied warranty, and with no claim as to its suitability for -any purpose.

    + +

    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.hpp b/scoped_ptr_example.hpp index 97c8bff..ae1fb8d 100644 --- a/scoped_ptr_example.hpp +++ b/scoped_ptr_example.hpp @@ -1,6 +1,6 @@ // 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 diff --git a/shared_array.htm b/shared_array.htm index 6de8704..8d21823 100644 --- a/shared_array.htm +++ b/shared_array.htm @@ -1,188 +1,223 @@ + + + shared_array - - -

    c++boost.gif (8819 bytes)Class -shared_array

    -

    Class shared_array 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 shared_array, on shared_array::operator=(), -or via an explicit shared_array::reset().  See example.

    -

    Class shared_array meets the CopyConstuctible -and Assignable requirements of the C++ Standard Library, and so -can be used in C++ Standard Library containers.  A specialization of std:: -less< > for  boost::shared_ptr<Y> is supplied so that  -shared_array works by default for Standard Library's Associative -Container Compare template parameter.  For compilers not supporting partial -specialization, the user must explicitly pass the less<> functor.

    -

    Class shared_array cannot correctly hold a pointer to a -single object.  See shared_ptr +

    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 +dynamically allocated array. See shared_ptr for that usage.

    -

    Class shared_array will not work correctly with cyclic data -structures. For example, if main() holds a shared_array pointing to array A, -which directly or indirectly holds a shared_array pointing back to array A, then -array A's use_count() will be 2, and destruction of the main() shared_array will -leave array A dangling with a use_count() of 1.

    -

    A C++ Standard Library vector is a -heavier duty alternative to a shared_array.

    -

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

    -

    Class shared_array Synopsis

    -
    #include <boost/smart_ptr.hpp>
    -namespace boost {
     
    -template<typename T> class shared_array {
    +

    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.

    - public: - typedef T element_type; +

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

    - explicit shared_array( T* p=0 ); - shared_array( const shared_array& ); // never throws - ~shared_array(); +

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

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

    Synopsis

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

    Specialization of std::swap uses the fast, non-throwing swap that's provided -as a member function instead of using the default algorithm which creates a -temporary and uses assignment.
    -
    -Specialization of std::less allows use of shared arrays as keys in C++ -Standard Library associative collections.
    -
    -The std::less specializations use std::less<T*> to perform the -comparison.  This insures that pointers are handled correctly, since the -standard mandates that relational operations on pointers are unspecified (5.9 [expr.rel] -paragraph 2) but std::less<> on pointers is well-defined (20.3.3 [lib.comparisons] -paragraph 8).
    -
    -It's still a controversial question whether supplying only std::less is better -than supplying a full range of comparison operators (<, >, <=, >=).

    -

    The current implementation does not supply the specializations if the macro -name BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION is defined.

    -

    Class shared_array Members

    -

    shared_array element_type

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

    -

    shared_array constructors

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

    Constructs a shared_array, storing a copy of p, -which must have been allocated via a C++ new[] expression or be 0. -Afterwards, use_count() is 1 (even if p==0; see ~shared_array).

    -

    The only exception which may be thrown is std::bad_alloc.  If -an exception is thrown,  delete[] p is called.

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

    Constructs a shared_array, as if by storing a copy of the -pointer stored in r. Afterwards, use_count() -for all copies is 1 more than the initial r.use_count().

    -

    shared_array destructor

    -
    ~shared_array();
    -

    If use_count() == 1, deletes the array pointed to by the -stored pointer. Otherwise, use_count() for any remaining -copies is decremented by 1. Note that in C++ delete[] on a pointer with -a value of 0 is harmless.

    -

    Does not throw exceptions.

    -

    shared_array operator=

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

    First, if use_count() == 1, deletes the array pointed to by -the stored pointer. Otherwise, use_count() for any -remaining copies is decremented by 1. Note that in C++ delete[] on a -pointer with a value of 0 is harmless.

    -

    Then replaces the contents of this, as if by storing a copy -of the pointer stored in r. Afterwards, use_count() -for all copies is 1 more than the initial r.use_count()

    -

    shared_array reset

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

    First, if use_count() == 1, deletes the array pointed to by -the stored pointer. Otherwise, use_count() for any -remaining copies is decremented by 1. Note that in C++  delete[] -on a pointer with a value of 0 is harmless.

    -

    Then replaces the contents of this, as if by storing a copy -of p, which must have been allocated via a C++ new[] -expression or be 0. Afterwards, use_count() is 1 (even if p==0; -see ~shared_array).

    -

    The only exception which may be thrown is std::bad_alloc.  If -an exception is thrown,  delete[] p is called.

    -

    shared_array operator[]

    -

    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 get()==0, -or if i is less than 0 or is greater or equal to the number of elements + +

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

    -

    shared_array get

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

    T is not required be a complete type.  -See Common Requirements.

    -

    Returns the stored pointer.

    -

    shared_array use_count

    -

    long use_count() const; // never throws

    -

    T is not required be a complete type.  -See Common Requirements.

    -

    Returns the number of shared_arrays sharing ownership of the -stored pointer.

    -

    shared_array unique

    -

    bool unique() const; // never throws

    -

    T is not required be a complete type.  -See Common Requirements.

    -

    Returns use_count() == 1.

    -

    shared_array swap

    -

    void swap( shared_array<T>& other ) throw()

    -

    T is not required be a complete type.  -See Common Requirements.

    -

    Swaps the two smart pointers, as if by std::swap.

    -

    Class shared_array example

    -

    [To be supplied. In the meantime, see smart_ptr_test.cpp.]

    + +

    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 24 May, 2001 -

    -

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, -modify, sell and distribute this document is granted provided this copyright -notice appears in all copies. This document is provided "as is" -without express or implied warranty, and with no claim as to its suitability for -any purpose.

    + +

    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/shared_ptr.htm b/shared_ptr.htm index 4913f65..fc6d0d6 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -1,284 +1,356 @@ + + + shared_ptr - - -

    -c++boost.gif (8819 bytes)Class -shared_ptr

    -

    Introduction
    -Synopsis

    +

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

    + +

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

    +

    Introduction

    -

    Class shared_ptr 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 deleted or reset.  -See example.

    -

    Class shared_ptr meets the CopyConstuctible -and Assignable requirements of the C++ Standard Library, and so -can be used in C++ Standard Library containers.  A specialization of std:: -less< > for  boost::shared_ptr<Y> is supplied so that  -shared_ptr works by default for Standard Library's Associative -Container Compare template parameter.  For compilers not supporting partial -specialization, the user must explicitly pass the less<> functor.

    -

    Class shared_ptr cannot correctly hold a pointer to a -dynamically allocated array.  See shared_array + +

    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.

    -

    Class shared_ptr will not work correctly with cyclic data -structures. For example, if main() holds a shared_ptr to object A, which -directly or indirectly holds a shared_ptr back to object A, then object A's -use_count() will be 2, and destruction of the main() shared_ptr will leave -object A dangling with a use_count() of 1.

    -

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

    -

    Class shared_ptr Synopsis

    -
    #include <boost/smart_ptr.hpp>
    -namespace boost {
     
    -template<typename T> class shared_ptr {
    +

    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.

    - public: - typedef T element_type; +

    The class template is parameterized on T, the type of the object +pointed to. T must meet the smart pointer +common requirements. +T may be void, but in that case, either an explicit delete +function must be passed in, or the pointed-to object must have a trivial destructor.

    - explicit shared_ptr( T* p=0 ); - ~shared_ptr(); +

    Synopsis

    - shared_ptr( const shared_ptr& ); - template<typename Y> - shared_ptr(const shared_ptr<Y>& r); // never throws - template<typename Y> - shared_ptr(std::auto_ptr<Y>& r); +
    namespace boost {
     
    -   shared_ptr& operator=( const shared_ptr& );  // never throws  
    -   template<typename Y>
    -      shared_ptr& operator=(const shared_ptr<Y>& r);  // never throws
    -   template<typename Y>
    -      shared_ptr& operator=(std::auto_ptr<Y>& r);
    +  template<typename T> class shared_ptr {
     
    -   void reset( T* p=0 );
    +    public:
    +      typedef T element_type;
     
    -   T& operator*() const;  // never throws
    -   T* operator->() const;  // never throws
    -   T* get() const;  // never throws
    +      explicit shared_ptr(T * p = 0);
    +      template<typename D> shared_ptr(T * p, D d);
    +      ~shared_ptr(); // never throws
     
    -   long use_count() const;  // never throws
    -   bool unique() const;  // never throws
    +      shared_ptr(shared_ptr const & r); // never throws
    +      template<typename Y> shared_ptr(shared_ptr<Y> const & r); // never throws
    +      template<typename Y> shared_ptr(std::auto_ptr<Y> & r);
     
    -   void swap( shared_ptr<T>& other ) throw()
    -   };
    +      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);
     
    -template<typename T, typename U>
    -  inline bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b)
    -    { return a.get() == b.get(); }
    +      void reset(T * p = 0); // never throws
    +      template<typename D> void reset(T * p, D d); // never throws
     
    -template<typename T, typename U>
    -  inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b)
    -    { return a.get() != b.get(); }
    -}
    -
    namespace std {
    +      T & operator*() const; // never throws
    +      T * operator->() const; // never throws
    +      T * get() const; // never throws
     
    -template<typename T>
    -  inline void swap(boost::shared_ptr<T>& a, boost::shared_ptr<T>& b)
    -    { a.swap(b); }
    +      bool unique() const; // never throws
    +      long use_count() const; // never throws
     
    -template<typename T>
    -  struct less< boost::shared_ptr<T> >
    -    : binary_function<boost::shared_ptr<T>, boost::shared_ptr<T>, bool>
    -  {
    -    bool operator()(const boost::shared_ptr<T>& a,
    -        const boost::shared_ptr<T>& b) const
    -      { return less<T*>()(a.get(),b.get()); }
    +      void swap(shared_ptr<T> & b); // never throws
       };
     
    -} // namespace std 
    -

    Specialization of std::swap uses the fast, non-throwing swap that's provided -as a member function instead of using the default algorithm which creates a -temporary and uses assignment.
    -
    -Specialization of std::less allows use of shared pointers as keys in C++ -Standard Library associative collections.
    -
    -The std::less specializations use std::less<T*> to perform the -comparison.  This insures that pointers are handled correctly, since the -standard mandates that relational operations on pointers are unspecified (5.9 [expr.rel] -paragraph 2) but std::less<> on pointers is well-defined (20.3.3 [lib.comparisons] -paragraph 8).
    -
    -It's still a controversial question whether supplying only std::less is better -than supplying a full range of comparison operators (<, >, <=, >=).

    -

    The current implementation does not supply the specializations if the macro -name BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION is defined.

    -

    The current implementation does not supply the member template functions if -the macro name BOOST_NO_MEMBER_TEMPLATES is defined.

    -

    Class shared_ptr Members

    -

    shared_ptr element_type

    + 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, typename U> + bool operator<(shared_ptr<T> const & a, shared_ptr<U> 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); + +}
    + +

    Members

    + +

    element_type

    typedef T element_type;

    Provides the type of the stored pointer.

    -

    shared_ptr constructors

    -
    explicit shared_ptr( T* p=0 );
    -

    Constructs a shared_ptr, storing a copy of p, which -must have been allocated via a C++ new expression or be 0. Afterwards, use_count() -is 1 (even if p==0; see ~shared_ptr).

    -

    The only exception which may be thrown by this constructor is std::bad_alloc.   -If an exception is thrown,  delete p is called.

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

    Constructs a shared_ptr, as if by storing a copy of the -pointer stored in r. Afterwards, use_count() -for all copies is 1 more than the initial r.use_count(), or 1 -in the auto_ptr case. In the auto_ptr case, r.release() -is called.

    -

    The only exception which may be thrown by the constructor from auto_ptr -is std::bad_alloc.   If an exception is thrown, that -constructor has no effect.

    -

    shared_ptr destructor

    -
    ~shared_ptr();
    -

    If use_count() == 1, deletes the object pointed to by the -stored pointer. Otherwise, use_count() for any remaining -copies is decremented by 1. Note that in C++  delete on a pointer -with a value of 0 is harmless.

    -

    Does not throw exceptions.

    -

    shared_ptr operator=

    -
    shared_ptr& operator=( const shared_ptr& r);  
    -template<typename Y>
    -   shared_ptr& operator=(const shared_ptr<Y>& r);
    -template<typename Y>
    -   shared_ptr& operator=(std::auto_ptr<Y>& r);
    -

    First, if use_count() == 1, deletes the object pointed to by -the stored pointer. Otherwise, use_count() for any -remaining copies is decremented by 1. Note that in C++  delete on -a pointer with a value of 0 is harmless.

    -

    Then replaces the contents of this, as if by storing a copy -of the pointer stored in r. Afterwards, use_count() -for all copies is 1 more than the initial r.use_count(), or 1 -in the auto_ptr case. In the auto_ptr case, r.release() -is called.

    -

    The first two forms of operator= above do not throw exceptions.

    -

    The only exception which may be thrown by the auto_ptr form -is std::bad_alloc.   If an exception is thrown, the function -has no effect.

    -

    shared_ptr reset

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

    First, if use_count() == 1, deletes the object pointed to by -the stored pointer. Otherwise, use_count() for any -remaining copies is decremented by 1. 

    -

    Then replaces the contents of this, as if by storing a copy -of p, which must have been allocated via a C++ new -expression or be 0. Afterwards, use_count() is 1 (even if p==0; -see ~shared_ptr). Note that in C++  delete -on a pointer with a value of 0 is harmless.

    -

    The only exception which may be thrown is std::bad_alloc.  If -an exception is thrown,  delete p is called.

    -

    shared_ptr operator*

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

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

    -

    shared_ptr operator-> and get

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

    T is not required by get() to be a complete type .  See Common Requirements.

    -

    Both return the stored pointer.

    -

    shared_ptr use_count

    -

    long use_count() const; // never throws

    -

    T is not required be a complete type.  -See Common Requirements.

    -

    Returns the number of shared_ptrs sharing ownership of the -stored pointer.

    -

    shared_ptr unique

    -

    bool unique() const; // never throws

    -

    T is not required be a complete type.  -See Common Requirements.

    -

    Returns use_count() == 1.

    -

    shared_ptr swap

    -

    void swap( shared_ptr<T>& other ) throw()

    -

    T is not required be a complete type.  -See Common Requirements.

    -

    Swaps the two smart pointers, as if by std::swap.

    -

    Class shared_ptr example

    -

    See shared_ptr_example.cpp for a complete example program.

    -

    This program builds a std::vector and std::set of FooPtr's.

    -

    Note that after the two containers have been populated, some of the FooPtr objects -will have use_count()==1 rather than use_count()==2, since foo_set is a std::set -rather than a std::multiset, and thus does not contain duplicate entries.  Furthermore, use_count() may be even higher -at various times while push_back() and insert() container operations are performed.  + +

    constructors

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

    Constructs a shared_ptr, storing a copy of p, which +must be a pointer to an object that was allocated via a C++ new expression or be 0. +Afterwards, the use count is 1 (even if p == 0; see ~shared_ptr). +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_ptr(T * p, D d);
    +

    Constructs a shared_ptr, storing a copy of p and of d. +Afterwards, the use count is 1. +D's copy constructor must not throw. +When the the time comes to delete the object 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_ptr(shared_ptr const & r); // never throws
    +template<typename Y> shared_ptr(shared_ptr<Y> const & r); // never throws
    +template<typename Y> shared_ptr(std::auto_ptr<Y> & r);
    +

    Constructs a shared_ptr, 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, or 1 +in the auto_ptr case. In the auto_ptr case, r.release() +is called. +The only exception which may be thrown is std::bad_alloc, +which may be thrown during construction from auto_ptr. +If an exception is thrown, the constructor has no effect.

    + +

    destructor

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

    Decrements the use count. Then, if the use count is 0, +deletes the object 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_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);
    +

    Constructs a new shared_ptr as described above, +then replaces this shared_ptr with the new one, destroying the replaced object. +The only exception which may be thrown is std::bad_alloc, +which may be thrown during assignment from auto_ptr. +If an exception is thrown, the assignment has no effect.

    + +

    reset

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

    Constructs a new shared_ptr as described above, +then replaces this shared_ptr 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_ptr as described above, +then replaces this shared_ptr 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.

    + +

    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.

    + +

    unique

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

    Returns true if no other shared_ptr 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_ptr 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_ptr 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, 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, typename U>
    +  bool operator<(shared_ptr<T> const & a, shared_ptr<U> 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_ptr +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_ptr<T> & a, shared_ptr<T> & b) // never throws
    +

    Equivalent to a.swap(b). 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
    +

    Perform a static_cast on the stored pointer, returning another shared_ptr. +The resulting smart pointer will share its use count with the original pointer.

    +

    Note that 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);
    +

    Perform a dynamic_cast on the stored pointer, returning another shared_ptr. +The resulting smart pointer will share its use count with the original pointer unless the result of the +cast is 0. The only exception which may be thrown is std::bad_alloc, which may be thrown during the +construction of the new shared_ptr if the result of the cast is 0. If an exception is thrown, the +cast has no effect.

    +

    Note that 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.

    + +

    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.  Without using a smart pointer, memory and -exception management would be a nightmare.

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

    +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. Why doesn't shared_ptr have template parameters supplying traits or policies to allow extensive user customization?
    -A. Parameterization discourages users.  Shared_ptr is +A. Parameterization discourages users. The shared_ptr template is carefully crafted to meet common needs without extensive parameterization. -Someday a highly configurable smart pointer may be invented that is also very -easy to use and very hard to misuse.  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.)

    +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. 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 +offset the added cost of an extra pointer. See timings page.

    -

    Q. Why don't shared_ptr (and the other Boost smart pointers) + +

    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 limit implementors and complicate the specification without apparent benefit to -shared_ptr users. For example, error-checking implementations might become non-conforming if they +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> 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.
    -
    -

    [Provided by Peter Dimov]

    +// 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 (or a link-list, or ...) implementation. This is not the intent. -[Provided by Peter Dimov]

    -


    -

    +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 11 January, 2002 -

    -

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, -modify, sell and distribute this document is granted provided this copyright -notice appears in all copies. This document is provided "as is" -without express or implied warranty, and with no claim as to its suitability for -any purpose.

    + +

    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.

    - \ No newline at end of file + diff --git a/shared_ptr_example.cpp b/shared_ptr_example.cpp index 988efbd..4db8fc6 100644 --- a/shared_ptr_example.cpp +++ b/shared_ptr_example.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include // The application will produce a series of // objects of type Foo which later must be diff --git a/shared_ptr_example2.cpp b/shared_ptr_example2.cpp index eddc806..746dd48 100644 --- a/shared_ptr_example2.cpp +++ b/shared_ptr_example2.cpp @@ -17,5 +17,3 @@ example & example::operator=( const example & s ) void example::do_something() { std::cout << "use_count() is " << _imp.use_count() << "\n"; } - -example::~example() {} diff --git a/shared_ptr_example2.hpp b/shared_ptr_example2.hpp index fea810b..93b77e5 100644 --- a/shared_ptr_example2.hpp +++ b/shared_ptr_example2.hpp @@ -1,6 +1,6 @@ // Boost shared_ptr_example2 header file -----------------------------------// -#include +#include // This example demonstrates the handle/body idiom (also called pimpl and // several other names). It separates the interface (in this header file) @@ -16,7 +16,6 @@ class example { public: example(); - ~example(); example( const example & ); example & operator=( const example & ); void do_something(); diff --git a/smart_ptr.htm b/smart_ptr.htm index 07538e4..0f5246d 100644 --- a/smart_ptr.htm +++ b/smart_ptr.htm @@ -1,126 +1,175 @@ + + - - -Smart Pointer Classes +Smart Pointers -

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

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

    -

    Smart pointers are classes which store pointers to dynamically allocated -(heap) objects.  They behave much like built-in C++ pointers except that + +

    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 +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 header boost/smart_ptr.hpp -provides four smart pointer template classes:

    + +

    The smart pointer library provides five smart pointer class templates:

    +
    - + + - - + + + - + + - + + + + + + +
    -

    scoped_ptr

    scoped_ptr<boost/scoped_ptr.hpp> Simple sole ownership of single objects. Noncopyable.
    scoped_arraySimple sole ownership of arrays. Noncopyable.scoped_array<boost/scoped_array.hpp>Simple sole ownership of arrays. Noncopyable.
    shared_ptrshared_ptr<boost/shared_ptr.hpp> Object ownership shared among multiple pointers
    shared_arrayshared_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 classes are designed to complement the C++ Standard Library auto_ptr -class.

    + +

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

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

    -

    A page on Smart Pointer Timings will be of + +

    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 classes have a template parameter, T, which -specifies the type of the object pointed to by the smart pointer.  The -behavior of all four classes 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 + +

    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 checked_delete().

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

    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.

    -

    Exception safety

    + +

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

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

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

    -

    All four classes contain member functions which can never throw exceptions, + +

    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.

    +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

    -

    May, 2001. Vladimir Prus suggested requiring a complete type on -destruction.  Refinement evolved in discussions including Dave Abrahams, +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 + +

    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.  See the -revision history in smart_ptr.hpp + +

    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. See the +revision history in smart_ptr.hpp for the specific changes made as a result of their constructive criticism.

    -

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

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

    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 +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.
    • @@ -129,22 +178,29 @@ elsewhere. Each of those variants have themselves two major variants:
    • 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 + +

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

    +

    See the Revision History section of the header for further contributors.

    +
    -

    Revised  24 May 20011 February 2002

    -

    İ Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, + +

    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 diff --git a/smart_ptr_test.cpp b/smart_ptr_test.cpp index 62c97ca..8d41070 100644 --- a/smart_ptr_test.cpp +++ b/smart_ptr_test.cpp @@ -13,13 +13,23 @@ // 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 #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 ) @@ -48,7 +58,7 @@ class UDT { explicit UDT( long value=0 ) : value_(value) { ++UDT_use_count; } ~UDT() { --UDT_use_count; - cout << "UDT with value " << value_ << " being destroyed" << endl; + cout << "UDT with value " << value_ << " being destroyed\n"; } long value() const { return value_; } void value( long v ) { value_ = v;; } @@ -71,7 +81,7 @@ Incomplete * check_incomplete( shared_ptr& incomplete, shared_ptr& i2 ) { incomplete.swap(i2); - cout << incomplete.use_count() << " " << incomplete.unique() << endl; + cout << incomplete.use_count() << ' ' << incomplete.unique() << '\n'; return incomplete.get(); } // main --------------------------------------------------------------------// @@ -186,12 +196,10 @@ int test_main( int, char ** ) { BOOST_TEST( *cp4 == 87654 ); BOOST_TEST( cp2.get() == 0 ); -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION set< shared_ptr > scp; scp.insert(cp4); BOOST_TEST( scp.find(cp4) != scp.end() ); BOOST_TEST( scp.find(cp4) == scp.find( shared_ptr(cp4) ) ); -#endif // test shared_array with a built-in type char * cap = new char [ 100 ]; @@ -232,12 +240,10 @@ int test_main( int, char ** ) { BOOST_TEST( strcmp( ca4.get(), "Not dog with mustard and relish" ) == 0 ); BOOST_TEST( ca3.get() == 0 ); -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION set< shared_array > sca; sca.insert(ca4); BOOST_TEST( sca.find(ca4) != sca.end() ); BOOST_TEST( sca.find(ca4) == sca.find( shared_array(ca4) ) ); -#endif // test shared_array with user defined type shared_array udta ( new UDT[3] ); @@ -280,7 +286,7 @@ int test_main( int, char ** ) { BOOST_TEST( sup.use_count() == 2 ); BOOST_TEST( sup2.use_count() == 2 ); - cout << "OK" << endl; + cout << "OK\n"; new char[12345]; // deliberate memory leak to verify leaks detected diff --git a/smart_ptr_test2.cpp b/smart_ptr_test2.cpp deleted file mode 100644 index 4ea305e..0000000 --- a/smart_ptr_test2.cpp +++ /dev/null @@ -1,295 +0,0 @@ -// 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" << endl; - } - long value() const { return value_; } - void value( long v ) { value_ = v;; } - }; // UDT - -// tests on incomplete types -----------------------------------------------// - -// Certain smart pointer operations are specified to work on incomplete types, -// and some uses depend upon this feature. These tests verify compilation -// only - the functions aren't actually invoked. - -class Incomplete; - -Incomplete * check_incomplete( scoped_ptr& incomplete ) -{ - return incomplete.get(); -} - -Incomplete * check_incomplete( shared_ptr& incomplete, - shared_ptr& i2 ) -{ - incomplete.swap(i2); - cout << incomplete.use_count() << " " << incomplete.unique() << endl; - return incomplete.get(); -} -// main --------------------------------------------------------------------// - -// This isn't a very systematic test; it just hits some of the basics. - -int test_main( int, char ** ) { - - BOOST_TEST( UDT_use_count == 0 ); // reality check - - // test scoped_ptr with a built-in type - long * lp = new long; - scoped_ptr 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" << endl; - - new char[12345]; // deliberate memory leak to verify leaks detected - - return 0; - } // main - diff --git a/smarttests.htm b/smarttests.htm index dcd8fda..84fd16e 100644 --- a/smarttests.htm +++ b/smarttests.htm @@ -1,13 +1,15 @@ + + + -boost: smart pointer tests +Smart Pointer Timings - + + -

    c++boost.gif (8819 bytes)Smart -Pointers 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 @@ -19,9 +21,10 @@ Pointers Timings 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 +

    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

    @@ -75,7 +78,7 @@ Pointers Timings   - + MSVC speed graph   @@ -85,7 +88,7 @@ Pointers Timings   - + GCC speed graph   @@ -530,7 +533,7 @@ Pointers Timings spreads its information as in the case of linked pointer.
    -

    Revised 19 Aug 2001 +

    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 diff --git a/weak_ptr.htm b/weak_ptr.htm new file mode 100644 index 0000000..fb97eac --- /dev/null +++ b/weak_ptr.htm @@ -0,0 +1,233 @@ + + + + + + +weak_ptr + + + + +

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

    + +

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

    + +

    Introduction

    + +

    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.

    + +

    Synopsis

    + +
    namespace boost {
    +
    +  template<typename T> class weak_ptr {
    +
    +    public:
    +      typedef T element_type;
    +
    +      explicit 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(); // never throws
    +
    +      T & operator*() const; // never throws
    +      T * operator->() const; // never throws
    +      T * get() const; // never throws
    +
    +      long use_count() 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, typename U>
    +    bool operator<(weak_ptr<T> const & a, weak_ptr<U> const & b); // never throws
    +
    +  template<typename T> void swap(weak_ptr<T> & a, weak_ptr<T> & b); // never throws
    +
    +  template<typename T, typename U>
    +    weak_ptr<T> shared_static_cast(weak_ptr<U> const & r); // never throws
    +  template<typename T, typename U>
    +    weak_ptr<T> shared_dynamic_cast(weak_ptr<U> const & r);
    +
    +}
    + +

    Members

    + +

    element_type

    +
    typedef T element_type;
    +

    Provides the type of the stored pointer.

    + +

    constructors

    + +
    explicit weak_ptr();
    +

    Constructs a weak_ptr, with 0 as its stored pointer. +The only exception which may be thrown by this constructor is std::bad_alloc. +If an exception is thrown, the constructor has no effect.

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

    Constructs a weak_ptr, as if by storing a copy of the pointer stored in r. +Afterwards, the use count for all copies is unchanged. +When the last shared_ptr is destroyed, the use count and stored pointer become 0. +The only exception which may be thrown by this constructor is std::bad_alloc. +If an exception is thrown, the constructor has no effect.

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

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

    + +

    destructor

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

    Destroys this weak_ptr but has no effect on the object its stored pointer points to. +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
    +

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

    + +

    reset

    + +
    void reset();
    +

    Constructs a new weak_ptr as described above, +then replaces this weak_ptr with the new one, destroying the replaced object. +The only exception which may be thrown is std::bad_alloc. If +an exception is thrown, the reset has no effect.

    + +

    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. +Note that the stored pointer becomes 0 if all shared_ptr objects for that +pointer are destroyed.

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

    Returns the stored pointer. +Behavior is undefined if the stored pointer is 0. +Note that the stored pointer becomes 0 if all shared_ptr objects for that +pointer are destroyed.

    + +

    get

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

    Returns the stored pointer. +Note that the stored pointer becomes 0 if all shared_ptr objects for that +pointer are destroyed. +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_ptr 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 weak_ptr 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 get should be used for +production code.

    + +

    swap

    +
    void swap(weak_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, 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, typename U>
    +  bool operator<(weak_ptr<T> const & a, weak_ptr<U> 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 weak_ptr +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(weak_ptr<T> & a, weak_ptr<T> & b) // never throws
    +

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

    + +

    shared_static_cast

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

    Perform a static_cast on the stored pointer, returning another weak_ptr. +The resulting smart pointer will share its use count with the original pointer.

    + +

    shared_dynamic_cast

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

    Perform a dynamic_cast on the stored pointer, returning another weak_ptr. +The resulting smart pointer will share its use count with the original pointer unless the result of the +cast is 0. The only exception which may be thrown is std::bad_alloc, which may be thrown during the +construction of the new weak_ptr if the result of the cast is 0. If an exception is thrown, the +cast has no effect.

    + +
    + +

    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.

    + + + + From ddd6d5442637e1f47f5b8eeb3c995d13f9d7b8e3 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sun, 3 Feb 2002 15:19:04 +0000 Subject: [PATCH 045/133] Need to include utility.hpp to get noncopyable [SVN r12669] --- scoped_ptr_example.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/scoped_ptr_example.hpp b/scoped_ptr_example.hpp index ae1fb8d..c4b6bf5 100644 --- a/scoped_ptr_example.hpp +++ b/scoped_ptr_example.hpp @@ -1,5 +1,6 @@ // Boost scoped_ptr_example header file ------------------------------------// +#include #include // The point of this example is to prove that even though From 590757e2b22b9a014ce37bc4d4902d8447115ed0 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sun, 3 Feb 2002 15:21:41 +0000 Subject: [PATCH 046/133] Don't give default arguments to function parameters what subsequent parameters do not have default arguments [SVN r12670] --- include/boost/shared_array.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/shared_array.hpp b/include/boost/shared_array.hpp index 4d400dc..3c8775f 100644 --- a/include/boost/shared_array.hpp +++ b/include/boost/shared_array.hpp @@ -75,7 +75,7 @@ public: this_type(p).swap(*this); } - template void reset(T * p = 0, D d) + template void reset(T * p, D d) { this_type(p, d).swap(*this); } From 758954a93f0ac047907ac58c4d3ea0a5df2580b1 Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Sun, 3 Feb 2002 17:46:08 +0000 Subject: [PATCH 047/133] Documentation updates. [SVN r12675] --- shared_array.htm | 2 +- shared_ptr.htm | 2 +- weak_ptr.htm | 11 ----------- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/shared_array.htm b/shared_array.htm index 8d21823..2b818e7 100644 --- a/shared_array.htm +++ b/shared_array.htm @@ -97,7 +97,7 @@ 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 must not throw. +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. diff --git a/shared_ptr.htm b/shared_ptr.htm index fc6d0d6..7773c2b 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -118,7 +118,7 @@ If an exception is thrown, delete p is called.

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

    Constructs a shared_ptr, storing a copy of p and of d. Afterwards, the use count is 1. -D's copy constructor must not throw. +D's copy constructor and destructor must not throw. When the the time comes to delete the object 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. diff --git a/weak_ptr.htm b/weak_ptr.htm index fb97eac..545195f 100644 --- a/weak_ptr.htm +++ b/weak_ptr.htm @@ -11,17 +11,6 @@

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

    -

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

    - -

    Introduction

    -

    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 From ee3d3bd1e199033c4ee55030aed6aa069ef86e01 Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Sun, 3 Feb 2002 17:50:11 +0000 Subject: [PATCH 048/133] Mention thread safety feature. [SVN r12676] --- compatibility.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compatibility.htm b/compatibility.htm index 65acfd7..fb4d0a5 100644 --- a/compatibility.htm +++ b/compatibility.htm @@ -58,7 +58,7 @@ Calling reset with a pointer to the object that's already owned by the

      -
    • The manipulation of use counts is now thread safe on Windows, Linux, and platforms +
    • The manipulation of use counts is now thread safe on Windows, Linux, and platforms that support pthreads. See the <boost/detail/atomic_count.hpp> file for details
    • From 6ed07733cba5f13abf631642a171aa9b3209a098 Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Mon, 4 Feb 2002 08:00:20 +0000 Subject: [PATCH 049/133] Fix atomic_count.hpp includes, convert Macintosh newlines to Unix ones, since Metrowerks supports either and the rest of Boost uses Unix ones. [SVN r12683] --- include/boost/detail/atomic_count.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/detail/atomic_count.hpp b/include/boost/detail/atomic_count.hpp index 0f33ac4..6486755 100644 --- a/include/boost/detail/atomic_count.hpp +++ b/include/boost/detail/atomic_count.hpp @@ -91,15 +91,15 @@ typedef long atomic_count; #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) -#include "atomic_count_win32.hpp" +#include #elif defined(linux) || defined(__linux) || defined(__linux__) -#include "atomic_count_linux.hpp" +#include #elif defined(BOOST_HAS_PTHREADS) -#include "atomic_count_pthreads.hpp" +#include #else From c29cc62d66616ef76e70f6d7250d868c4fcf1e78 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 4 Feb 2002 11:15:40 +0000 Subject: [PATCH 050/133] Minor tweaks. [SVN r12684] --- include/boost/detail/shared_array_nmt.hpp | 2 +- include/boost/detail/shared_ptr_nmt.hpp | 2 +- include/boost/scoped_array.hpp | 3 ++- include/boost/scoped_ptr.hpp | 3 ++- include/boost/shared_array.hpp | 2 +- include/boost/shared_ptr.hpp | 4 +++- include/boost/weak_ptr.hpp | 4 +++- weak_ptr.htm | 4 +--- 8 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/boost/detail/shared_array_nmt.hpp b/include/boost/detail/shared_array_nmt.hpp index 570af13..3ff1954 100644 --- a/include/boost/detail/shared_array_nmt.hpp +++ b/include/boost/detail/shared_array_nmt.hpp @@ -12,7 +12,7 @@ // 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. +// See http://www.boost.org/libs/smart_ptr/shared_array.htm for documentation. // #include diff --git a/include/boost/detail/shared_ptr_nmt.hpp b/include/boost/detail/shared_ptr_nmt.hpp index 5364e77..79d5b5d 100644 --- a/include/boost/detail/shared_ptr_nmt.hpp +++ b/include/boost/detail/shared_ptr_nmt.hpp @@ -12,7 +12,7 @@ // 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. +// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. // #include diff --git a/include/boost/scoped_array.hpp b/include/boost/scoped_array.hpp index 74ecebe..c4fa3d0 100644 --- a/include/boost/scoped_array.hpp +++ b/include/boost/scoped_array.hpp @@ -9,7 +9,8 @@ // 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. +// See http://www.boost.org/libs/smart_ptr/scoped_array.htm for documentation. +// #include #include // in case ptrdiff_t not in std diff --git a/include/boost/scoped_ptr.hpp b/include/boost/scoped_ptr.hpp index 6648f09..e2a3ddf 100644 --- a/include/boost/scoped_ptr.hpp +++ b/include/boost/scoped_ptr.hpp @@ -9,7 +9,8 @@ // 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. +// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation. +// #include diff --git a/include/boost/shared_array.hpp b/include/boost/shared_array.hpp index 3c8775f..a820abc 100644 --- a/include/boost/shared_array.hpp +++ b/include/boost/shared_array.hpp @@ -12,7 +12,7 @@ // 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. +// See http://www.boost.org/libs/smart_ptr/shared_array.htm for documentation. // #include // for broken compiler workarounds diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index d601bab..e6411c3 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -12,7 +12,7 @@ // 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. +// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. // #include // for broken compiler workarounds @@ -109,7 +109,9 @@ public: 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(static_cast(0), deleter()); + } } #ifndef BOOST_NO_AUTO_PTR diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index 087ab12..f96856a 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -11,7 +11,7 @@ // 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. +// See http://www.boost.org/libs/smart_ptr/weak_ptr.htm for documentation. // #include @@ -68,7 +68,9 @@ public: weak_ptr(weak_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::weak_count(); + } } template diff --git a/weak_ptr.htm b/weak_ptr.htm index 545195f..10a0c2c 100644 --- a/weak_ptr.htm +++ b/weak_ptr.htm @@ -90,9 +90,7 @@ If an exception is thrown, the constructor has no effect.

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

      Constructs a weak_ptr, as if by storing a copy of the pointer stored in r. Afterwards, the use count for all copies is unchanged. -When the last shared_ptr is destroyed, the use count and stored pointer become 0. -The only exception which may be thrown by this constructor is std::bad_alloc. -If an exception is thrown, the constructor has no effect.

      +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
      From 08df55159baad83c9ccfa9166bac4bd78d0d3383 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Mon, 4 Feb 2002 18:51:16 +0000 Subject: [PATCH 051/133] Fix broken links [SVN r12697] --- smart_ptr.htm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/smart_ptr.htm b/smart_ptr.htm index 0f5246d..682a675 100644 --- a/smart_ptr.htm +++ b/smart_ptr.htm @@ -29,27 +29,27 @@ thus responsible for deletion of the object when it is no longer needed.

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


      Revised 1 February 200204 February 2002

      Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. From e1567707b1f6921cd796236b08bac52dcdd259f4 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 4 Feb 2002 19:45:11 +0000 Subject: [PATCH 052/133] Tab removed :-) [SVN r12701] --- smart_ptr_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smart_ptr_test.cpp b/smart_ptr_test.cpp index 8d41070..baee93d 100644 --- a/smart_ptr_test.cpp +++ b/smart_ptr_test.cpp @@ -27,7 +27,7 @@ bool boost_error(char const *, char const *, char const *, long) { - return true; // fail with assert() + return true; // fail with assert() } class Incomplete; From f9782387d9524b91092a7df63f4e8ccf4524c3e3 Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Mon, 4 Feb 2002 22:52:48 +0000 Subject: [PATCH 053/133] Tweaks. [SVN r12715] --- include/boost/scoped_array.hpp | 6 +++--- shared_array.htm | 4 ++-- shared_ptr.htm | 4 ++-- smart_ptr.htm | 2 +- weak_ptr.htm | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/boost/scoped_array.hpp b/include/boost/scoped_array.hpp index c4fa3d0..6734c5e 100644 --- a/include/boost/scoped_array.hpp +++ b/include/boost/scoped_array.hpp @@ -27,7 +27,7 @@ template class scoped_array // noncopyable { private: - T* ptr; + T * ptr; scoped_array(scoped_array const &); scoped_array & operator=(scoped_array const &); @@ -57,14 +57,14 @@ public: } } - T& operator[](std::ptrdiff_t i) const // never throws + 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 + T * get() const // never throws { return ptr; } diff --git a/shared_array.htm b/shared_array.htm index 2b818e7..12c353e 100644 --- a/shared_array.htm +++ b/shared_array.htm @@ -197,10 +197,10 @@ 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 +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 2) but std::less<> on pointers is well-defined (20.3.3 [lib.comparisons] paragraph 8).

      swap

      diff --git a/shared_ptr.htm b/shared_ptr.htm index 7773c2b..42e23fe 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -230,10 +230,10 @@ See the smart pointer common requirements.

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

      swap

      diff --git a/smart_ptr.htm b/smart_ptr.htm index 682a675..c6782a4 100644 --- a/smart_ptr.htm +++ b/smart_ptr.htm @@ -196,7 +196,7 @@ implementation.


      Revised 04 February 20024 February 2002

      Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. diff --git a/weak_ptr.htm b/weak_ptr.htm index 10a0c2c..a28232b 100644 --- a/weak_ptr.htm +++ b/weak_ptr.htm @@ -178,10 +178,10 @@ See the smart pointer common requirements.

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

      swap

      From 0dd3285d5668ca25da0858ca9cce80a972a5d6dd Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Wed, 6 Feb 2002 19:42:04 +0000 Subject: [PATCH 054/133] New casts for smart pointers. [SVN r12743] --- include/boost/shared_ptr.hpp | 23 ++++++++++++++++++++++- include/boost/weak_ptr.hpp | 20 ++++++++++++++++++++ shared_ptr.htm | 24 ++++++++++++++++++++++-- weak_ptr.htm | 24 ++++++++++++++++++++++-- 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index e6411c3..c13c3a8 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -43,6 +43,7 @@ namespace detail struct static_cast_tag {}; struct dynamic_cast_tag {}; +struct polymorphic_cast_tag {}; template struct shared_ptr_traits { @@ -114,6 +115,15 @@ public: } } + 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 @@ -219,7 +229,7 @@ template inline bool operator<(shared_ptr const & a, shared_ptr()(a.get(), b.get()); } -template void swap(shared_ptr & a, shared_ptr & b) +template inline void swap(shared_ptr & a, shared_ptr & b) { a.swap(b); } @@ -234,6 +244,17 @@ template shared_ptr shared_dynamic_cast(shared_ptr 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) diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index f96856a..c96d097 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -73,6 +73,15 @@ public: } } + template + weak_ptr(weak_ptr const & r, detail::polymorphic_cast_tag): px(dynamic_cast(r.px)), pn(r.pn) + { + if (px == 0) + { + throw std::bad_cast(); + } + } + template weak_ptr & operator=(weak_ptr const & r) // never throws { @@ -170,6 +179,17 @@ template weak_ptr shared_dynamic_cast(weak_ptr const & r return weak_ptr(r, detail::dynamic_cast_tag()); } +template weak_ptr shared_polymorphic_cast(weak_ptr const & r) +{ + return weak_ptr(r, detail::polymorphic_cast_tag()); +} + +template weak_ptr shared_polymorphic_downcast(weak_ptr const & r) +{ + BOOST_ASSERT(dynamic_cast(r.get()) == r.get()); + return shared_static_cast(r); +} + // get_pointer() enables boost::mem_fn to recognize weak_ptr template inline T * get_pointer(weak_ptr const & p) diff --git a/shared_ptr.htm b/shared_ptr.htm index 42e23fe..0e9d426 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -97,6 +97,10 @@ function must be passed in, or the pointed-to object must have a trivial destruc 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 }
    @@ -244,7 +248,7 @@ 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
    + shared_ptr<T> shared_static_cast(shared_ptr<U> const & r); // never throws

    Perform a static_cast on the stored pointer, returning another shared_ptr. The resulting smart pointer will share its use count with the original pointer.

    Note that the seemingly equivalent expression

    @@ -253,7 +257,7 @@ The resulting smart pointer will share its use count with the original pointer.<

    shared_dynamic_cast

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

    Perform a dynamic_cast on the stored pointer, returning another shared_ptr. The resulting smart pointer will share its use count with the original pointer unless the result of the cast is 0. The only exception which may be thrown is std::bad_alloc, which may be thrown during the @@ -263,6 +267,22 @@ cast has no effect.

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

    Perform a polymorphic_cast on the stored pointer, +returning another shared_ptr. +The resulting smart pointer will share its use count with the original pointer. +The only exception which may be thrown is std::bad_cast, if the pointer type can not be converted. +If an exception is thrown, the cast has no effect.

    + +

    shared_polymorphic_downcast

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

    Perform a polymorphic_downcast on the stored pointer, +returning another shared_ptr. +The resulting smart pointer will share its use count with the original pointer.

    +

    Example

    See shared_ptr_example.cpp for a complete example program. diff --git a/weak_ptr.htm b/weak_ptr.htm index a28232b..ccedf19 100644 --- a/weak_ptr.htm +++ b/weak_ptr.htm @@ -71,6 +71,10 @@ pointed to. T must meet the smart pointer weak_ptr<T> shared_static_cast(weak_ptr<U> const & r); // never throws template<typename T, typename U> weak_ptr<T> shared_dynamic_cast(weak_ptr<U> const & r); + template<typename T, typename U> + weak_ptr<T> shared_polymorphic_cast(weak_ptr<U> const & r); + template<typename T, typename U> + weak_ptr<T> shared_polymorphic_downcast(weak_ptr<U> const & r); // never throws }

    @@ -192,19 +196,35 @@ Provided as an aid to generic programming.

    shared_static_cast

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

    Perform a static_cast on the stored pointer, returning another weak_ptr. The resulting smart pointer will share its use count with the original pointer.

    shared_dynamic_cast

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

    Perform a dynamic_cast on the stored pointer, returning another weak_ptr. The resulting smart pointer will share its use count with the original pointer unless the result of the cast is 0. The only exception which may be thrown is std::bad_alloc, which may be thrown during the construction of the new weak_ptr if the result of the cast is 0. If an exception is thrown, the cast has no effect.

    +

    shared_polymorphic_cast

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

    Perform a polymorphic_cast on the stored pointer, +returning another weak_ptr. +The resulting smart pointer will share its use count with the original pointer. +The only exception which may be thrown is std::bad_cast, if the pointer type can not be converted. +If an exception is thrown, the cast has no effect.

    + +

    shared_polymorphic_downcast

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

    Perform a polymorphic_downcast on the stored pointer, +returning another weak_ptr. +The resulting smart pointer will share its use count with the original pointer.

    +

    Revised 1 February 2002

    From 2a2f10fddda938029638387dc5ff1e4c52ba590e Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 8 Feb 2002 18:40:49 +0000 Subject: [PATCH 055/133] Borland 5.5.1 fix [SVN r12761] --- include/boost/weak_ptr.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index c96d097..170359d 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -110,14 +110,14 @@ public: typename detail::shared_ptr_traits::reference operator* () const // never throws { - T * p = get(); + element_type * p = get(); BOOST_ASSERT(p != 0); return *p; } T * operator-> () const // never throws { - T * p = get(); + element_type * p = get(); BOOST_ASSERT(p != 0); return p; } From 7add76dae81b8430d3f21d426b708ed29ee5ea99 Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Fri, 8 Feb 2002 20:08:15 +0000 Subject: [PATCH 056/133] Always say "private noncopyable" to avoid warnings. [SVN r12762] --- scoped_ptr_example.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scoped_ptr_example.hpp b/scoped_ptr_example.hpp index c4b6bf5..d3009f7 100644 --- a/scoped_ptr_example.hpp +++ b/scoped_ptr_example.hpp @@ -9,7 +9,7 @@ // is complete where it counts - in the inplementation translation unit where // destruction is actually instantiated. -class example : boost::noncopyable +class example : private boost::noncopyable { public: example(); From 87f0accb23348282619dea861c8d354e5720ed69 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 8 Feb 2002 20:45:04 +0000 Subject: [PATCH 057/133] Minor fixes. [SVN r12763] --- shared_array.htm | 6 +++--- shared_ptr.htm | 12 ++++++------ weak_ptr.htm | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/shared_array.htm b/shared_array.htm index 12c353e..6ecc911 100644 --- a/shared_array.htm +++ b/shared_array.htm @@ -54,10 +54,10 @@ pointed to. T must meet the smart pointer
    shared_array(shared_array const & r); // never throws - shared_array & operator=(shared_array const & r); // never throws + shared_array & operator=(shared_array const & r); // never throws - void reset(T * p = 0); // never throws - template<typename D> void reset(T * p, D d); // 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 diff --git a/shared_ptr.htm b/shared_ptr.htm index 0e9d426..3f4c366 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -71,8 +71,8 @@ function must be passed in, or the pointed-to object must have a trivial destruc 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(T * p = 0); // never throws - template<typename D> void reset(T * p, D d); // never throws + void reset(T * p = 0); + template<typename D> void reset(T * p, D d); T & operator*() const; // never throws T * operator->() const; // never throws @@ -88,8 +88,8 @@ function must be passed in, or the pointed-to object must have a trivial destruc 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, 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 @@ -226,8 +226,8 @@ See the smart pointer 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, 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

    Compares the stored pointers of the two smart pointers. T need not be a complete type. See the smart pointer diff --git a/weak_ptr.htm b/weak_ptr.htm index ccedf19..25ae561 100644 --- a/weak_ptr.htm +++ b/weak_ptr.htm @@ -47,7 +47,7 @@ pointed to. T must meet the smart pointer 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(); // never throws + void reset(); T & operator*() const; // never throws T * operator->() const; // never throws @@ -62,8 +62,8 @@ pointed to. T must meet the smart pointer 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, 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 @@ -174,8 +174,8 @@ See the smart pointer 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, 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

    Compares the stored pointers of the two smart pointers. T need not be a complete type. See the smart pointer From a6126b137029205c49e5598ce1767d6f402e1875 Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Sat, 9 Feb 2002 01:18:00 +0000 Subject: [PATCH 058/133] Fixed some broken internal links. [SVN r12766] --- shared_array.htm | 16 ++++++++-------- shared_ptr.htm | 14 +++++++------- weak_ptr.htm | 16 ++++++++-------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/shared_array.htm b/shared_array.htm index 6ecc911..3319553 100644 --- a/shared_array.htm +++ b/shared_array.htm @@ -23,7 +23,7 @@ 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 -dynamically allocated array. See shared_ptr +single dynamically allocated object. See shared_ptr for that usage.

    Because the implementation uses reference counting, shared_array will not work @@ -69,11 +69,11 @@ pointed to. T must meet the smart pointer }; template<typename T> - bool operator==(shared_array<T> const & a, shared_array<T> const & b); // never throws + 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 + 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 + 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 @@ -186,11 +186,11 @@ See the smart pointer

    comparison

    template<typename T>
    -  bool operator==(shared_array<T> const & a, shared_array<T> const & b); // never throws
    +  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
    +  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
    + 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 @@ -211,7 +211,7 @@ Provided as an aid to generic programming.


    -

    Revised 1 February 2002

    +

    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 diff --git a/shared_ptr.htm b/shared_ptr.htm index 3f4c366..0cc96f1 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -85,11 +85,11 @@ function must be passed in, or the pointed-to object must have a trivial destruc }; template<typename T, typename U> - bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws + 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 + 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 + 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 @@ -223,11 +223,11 @@ See the smart pointer

    comparison

    template<typename T, typename U>
    -  bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
    +  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
    +  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
    + bool operator<(shared_ptr<T> const & a, shared_ptr<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 @@ -363,7 +363,7 @@ This is not the intent.


    -

    Revised 1 February 2002

    +

    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 diff --git a/weak_ptr.htm b/weak_ptr.htm index 25ae561..9ef44d4 100644 --- a/weak_ptr.htm +++ b/weak_ptr.htm @@ -36,7 +36,7 @@ pointed to. T must meet the smart pointer public: typedef T element_type; - explicit weak_ptr(); + weak_ptr(); template<typename Y> weak_ptr(shared_ptr<Y> const & r); // never throws ~weak_ptr(); // never throws @@ -59,11 +59,11 @@ pointed to. T must meet the smart pointer }; template<typename T, typename U> - bool operator==(weak_ptr<T> const & a, weak_ptr<U> const & b); // never throws + 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 + 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 + 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 @@ -171,11 +171,11 @@ See the smart pointer

    comparison

    template<typename T, typename U>
    -  bool operator==(weak_ptr<T> const & a, weak_ptr<U> const & b); // never throws
    +  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
    +  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
    + bool operator<(weak_ptr<T> const & a, weak_ptr<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 @@ -227,7 +227,7 @@ The resulting smart pointer will share its use count with the original pointer.<


    -

    Revised 1 February 2002

    +

    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 From d2e20cf56cdaf6d41e071b67a8cbd7fa66cfdf68 Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Sat, 9 Feb 2002 02:54:00 +0000 Subject: [PATCH 059/133] Remove obsolete paragraph [SVN r12767] --- smart_ptr.htm | 2 -- 1 file changed, 2 deletions(-) diff --git a/smart_ptr.htm b/smart_ptr.htm index c6782a4..ce7e38e 100644 --- a/smart_ptr.htm +++ b/smart_ptr.htm @@ -191,8 +191,6 @@ preferred, and that was also experimented with.

    discourage users", and in the end we choose to supply only the direct implementation.

    -

    See the Revision History section of the header for further contributors.

    -

    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.

    - - - +// 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  + 14 February 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.

    + From 5e2f514140fe9c9d9e2809714bb3cc4ff59960a3 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 14 Feb 2002 23:08:30 +0000 Subject: [PATCH 067/133] Added forward declaration of 'weak_count' class, which is referenced in shared_count; the friend declaration does not suffice to forward-declare the name. [SVN r12813] --- include/boost/detail/shared_count.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 120fd47..2e0dc47 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -174,6 +174,7 @@ public: } }; +class weak_count; class shared_count { From 5a6cd1cf3ee66077dc14ca17a421f6869859197d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 15 Feb 2002 13:31:58 +0000 Subject: [PATCH 068/133] Added a default constructor to shared_count and shared_ptr for incomplete types (void). [SVN r12815] --- include/boost/detail/shared_count.hpp | 6 +++- include/boost/shared_ptr.hpp | 15 ++++++-- shared_ptr.htm | 50 +++++++++++++++++++++------ 3 files changed, 57 insertions(+), 14 deletions(-) diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 2e0dc47..d513329 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -186,6 +186,10 @@ private: public: + shared_count(): pi_(new counted_base(1, 1)) + { + } + template shared_count(P p, D d): pi_(0) { try @@ -221,7 +225,7 @@ public: pi_->add_ref(); } - explicit shared_count(weak_count const & r); // throws bad_weak_to_shared_cast when r.use_count() == 0 + 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 { diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index bd0fcff..e2ddb94 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -81,7 +81,11 @@ public: typedef T element_type; - explicit shared_ptr(T * p = 0): px(p), pn(p, deleter()) + shared_ptr(): px(0), pn() + { + } + + explicit shared_ptr(T * p): px(p), pn(p, deleter()) // requires complete type { } @@ -157,9 +161,14 @@ public: #endif - void reset(T * p = 0) + void reset() { - BOOST_ASSERT(p == 0 || p != px); + this_type().swap(*this); + } + + void reset(T * p) // requires complete type + { + BOOST_ASSERT(p == 0 || p != px); // catch self-reset errors this_type(p).swap(*this); } diff --git a/shared_ptr.htm b/shared_ptr.htm index be3b1c5..ae1c36d 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -40,6 +40,8 @@

    Synopsis

    namespace boost {
     
    +  class use_count_is_zero: public std::exception;
    +
       template<typename T> class weak_ptr;
     
       template<typename T> class shared_ptr {
    @@ -47,20 +49,22 @@
         public:
           typedef T element_type;
     
    -      explicit shared_ptr(T * p = 0);
    +      shared_ptr ();
    +      explicit shared_ptr (T * p); // requires complete type
           template<typename D> shared_ptr(T * 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
    -      shared_ptr(weak_ptr const & r);
    +      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(T * p = 0);
    +      void reset ();
    +      void reset (T * p); // requires complete type
           template<typename D> void reset(T * p, D d);
     
           T & operator*() const; // never throws
    @@ -99,7 +103,18 @@
     			

    Provides the type of the template parameter T.

    constructors

    -
    explicit shared_ptr(T * p = 0);
    +
    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.

    +

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

    +
    +
    explicit shared_ptr(T * p);

    Requirements: The expression delete p must be well-formed and must not invoke undefined behavior. @@ -136,7 +151,7 @@ template<typename Y> shared_ptr(shared_ptr<Y> const & r); // nev increased by one.

    Throws: nothing.

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

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

    @@ -174,11 +189,26 @@ template<typename Y> shared_ptr & operator=(shared_ptr<Y> const 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(T * p = 0);
    +
    void reset();
    +
    +

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

    +
    +
    void reset(T * p);

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

    +

    Notes: Note the implied requirement that T is a complete type.

    template<typename D> void reset(T * p, D d);
    @@ -312,8 +342,8 @@ template<typename Y> shared_ptr & operator=(std::auto_ptr<Y> &am 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.

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

    @@ -325,8 +355,8 @@ template<typename Y> shared_ptr & operator=(std::auto_ptr<Y> &am 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.

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

    From adc3ec3851eb3d86b99a55db8cee7783f195f194 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 15 Feb 2002 14:19:30 +0000 Subject: [PATCH 069/133] Fixes. [SVN r12816] --- include/boost/shared_ptr.hpp | 2 +- shared_ptr.htm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index e2ddb94..0c00e9a 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -120,7 +120,7 @@ public: { if (px == 0) // need to allocate new counter -- the cast failed { - pn = detail::shared_count(static_cast(0), deleter()); + pn = detail::shared_count(); } } diff --git a/shared_ptr.htm b/shared_ptr.htm index ae1c36d..ff3e5aa 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -347,7 +347,7 @@ q = p;

    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.

    +

    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

    From 862dc0001fb6baa0dad292986a7b6369b1fc3564 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 15 Feb 2002 14:46:53 +0000 Subject: [PATCH 070/133] Documented the bool conversion. [SVN r12817] --- shared_ptr.htm | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index ff3e5aa..8dbd3a1 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -74,6 +74,8 @@ 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 }; @@ -255,6 +257,17 @@ q = p; be a complete type. See the smart pointer common requirements.

    +

    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
    @@ -284,7 +297,7 @@ q = p;
    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< +

    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.

    @@ -347,7 +360,8 @@ q = p;

    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.

    +

    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

    From 875bab352c9582f8699591a55cc7c2e479e4ba0c Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 15 Feb 2002 18:06:17 +0000 Subject: [PATCH 071/133] Added a timing test for the single/multi threaded perf ratio (~2:1) [SVN r12821] --- shared_ptr_timing_test.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 shared_ptr_timing_test.cpp diff --git a/shared_ptr_timing_test.cpp b/shared_ptr_timing_test.cpp new file mode 100644 index 0000000..d456eaf --- /dev/null +++ b/shared_ptr_timing_test.cpp @@ -0,0 +1,23 @@ +#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'; +} From 7981b647c31310cbc23d417d752a62ee7986478f Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 15 Feb 2002 18:07:42 +0000 Subject: [PATCH 072/133] lwm_nop fixed to not emit warnings on g++; locking code #ifdef'ed since compilers sometimes have trouble removing it. [SVN r12822] --- include/boost/detail/lwm_nop.hpp | 23 +---------------------- include/boost/detail/shared_count.hpp | 12 ++++++++++++ 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/include/boost/detail/lwm_nop.hpp b/include/boost/detail/lwm_nop.hpp index 1d798e0..671a5b0 100644 --- a/include/boost/detail/lwm_nop.hpp +++ b/include/boost/detail/lwm_nop.hpp @@ -24,30 +24,9 @@ namespace detail class lightweight_mutex { -private: - - lightweight_mutex(lightweight_mutex const &); - lightweight_mutex & operator=(lightweight_mutex const &); - public: - lightweight_mutex() - { - } - - class scoped_lock - { - private: - - scoped_lock(scoped_lock const &); - scoped_lock & operator=(scoped_lock const &); - - public: - - explicit scoped_lock(lightweight_mutex &) - { - } - }; + typedef lightweight_mutex scoped_lock; }; } // namespace detail diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index d513329..9dfed4f 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -74,7 +74,9 @@ public: void add_ref() { +#ifdef BOOST_HAS_THREADS lightweight_mutex::scoped_lock lock(mtx_); +#endif if(use_count_ == 0) throw use_count_is_zero(); ++use_count_; ++weak_count_; @@ -86,7 +88,9 @@ public: long new_weak_count; { +#ifdef BOOST_HAS_THREADS lightweight_mutex::scoped_lock lock(mtx_); +#endif new_use_count = --use_count_; new_weak_count = --weak_count_; } @@ -106,7 +110,9 @@ public: void weak_add_ref() // nothrow { +#ifdef BOOST_HAS_THREADS lightweight_mutex::scoped_lock lock(mtx_); +#endif ++weak_count_; } @@ -115,7 +121,9 @@ public: long new_weak_count; { +#ifdef BOOST_HAS_THREADS lightweight_mutex::scoped_lock lock(mtx_); +#endif new_weak_count = --weak_count_; } @@ -127,7 +135,9 @@ public: long use_count() const // nothrow { +#ifdef BOOST_HAS_THREADS lightweight_mutex::scoped_lock lock(mtx_); +#endif return use_count_; } @@ -145,7 +155,9 @@ private: long use_count_; long weak_count_; +#ifdef BOOST_HAS_THREADS mutable lightweight_mutex mtx_; +#endif void (*self_deleter_) (counted_base *); }; From 2482e00224cf678e4e8363523bebbc53b56d7201 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 16 Feb 2002 13:23:01 +0000 Subject: [PATCH 073/133] Modified scoped_* to use checked_delete; HP aCC doesn't like the inline assertions. [SVN r12832] --- include/boost/scoped_array.hpp | 8 +++----- include/boost/scoped_ptr.hpp | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/include/boost/scoped_array.hpp b/include/boost/scoped_array.hpp index 6734c5e..070925c 100644 --- a/include/boost/scoped_array.hpp +++ b/include/boost/scoped_array.hpp @@ -13,6 +13,7 @@ // #include +#include #include // in case ptrdiff_t not in std #include // for std::ptrdiff_t @@ -42,17 +43,14 @@ public: ~scoped_array() // never throws { - typedef char type_must_be_complete[sizeof(T)]; - delete [] ptr; + checked_array_delete(ptr); } void reset(T * p = 0) // never throws { - typedef char type_must_be_complete[sizeof(T)]; - if (ptr != p) { - delete [] ptr; + checked_array_delete(ptr); ptr = p; } } diff --git a/include/boost/scoped_ptr.hpp b/include/boost/scoped_ptr.hpp index e2a3ddf..f452f7a 100644 --- a/include/boost/scoped_ptr.hpp +++ b/include/boost/scoped_ptr.hpp @@ -13,6 +13,7 @@ // #include +#include namespace boost { @@ -41,17 +42,14 @@ public: ~scoped_ptr() // never throws { - typedef char type_must_be_complete[sizeof(T)]; - delete ptr; + checked_delete(ptr); } void reset(T * p = 0) // never throws { - typedef char type_must_be_complete[sizeof(T)]; - if (ptr != p) { - delete ptr; + checked_delete(ptr); ptr = p; } } From 6e6a2a013afeee29f7c5f3de6d73686c13b8da6a Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 16 Feb 2002 14:34:34 +0000 Subject: [PATCH 074/133] Added lwm_linux.hpp [SVN r12833] --- include/boost/detail/lwm_linux.hpp | 78 ++++++++++++++++++++++++++++++ include/boost/detail/lwm_win32.hpp | 11 ++--- 2 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 include/boost/detail/lwm_linux.hpp diff --git a/include/boost/detail/lwm_linux.hpp b/include/boost/detail/lwm_linux.hpp new file mode 100644 index 0000000..c2ef69a --- /dev/null +++ b/include/boost/detail/lwm_linux.hpp @@ -0,0 +1,78 @@ +#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. +// + +#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_win32.hpp b/include/boost/detail/lwm_win32.hpp index 2a29c3d..60388d5 100644 --- a/include/boost/detail/lwm_win32.hpp +++ b/include/boost/detail/lwm_win32.hpp @@ -22,13 +22,10 @@ namespace boost namespace detail { -// Avoid #including +// avoid including -namespace win32 -{ extern "C" __declspec(dllimport) long __stdcall InterlockedExchange(long volatile *, long); extern "C" __declspec(dllimport) void __stdcall Sleep(unsigned long); -} class lightweight_mutex { @@ -61,14 +58,14 @@ public: explicit scoped_lock(lightweight_mutex & m): m_(m) { - while( win32::InterlockedExchange(&m_.l_, 1) ) win32::Sleep(0); + while( InterlockedExchange(&m_.l_, 1) ) Sleep(0); } ~scoped_lock() { - win32::InterlockedExchange(&m_.l_, 0); + InterlockedExchange(&m_.l_, 0); - // Note: adding a win32::Sleep(0) here will make + // Note: adding a Sleep(0) here will make // the mutex more fair and will increase the overall // performance of the application substantially in // high contention situations, but will penalize the From 76c19e6111d197fb7fdd09aa2d2623f1b3667c17 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 16 Feb 2002 15:00:55 +0000 Subject: [PATCH 075/133] Enabled lwm_linux.hpp in lightweight_mutex.hpp. [SVN r12834] --- include/boost/detail/lightweight_mutex.hpp | 4 ++-- include/boost/detail/lwm_linux.hpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/boost/detail/lightweight_mutex.hpp b/include/boost/detail/lightweight_mutex.hpp index 9f80b00..d4ef1c1 100644 --- a/include/boost/detail/lightweight_mutex.hpp +++ b/include/boost/detail/lightweight_mutex.hpp @@ -38,8 +38,8 @@ # include #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) # include -//#elif defined(linux) || defined(__linux) || defined(__linux__) -//# include +#elif defined(linux) || defined(__linux) || defined(__linux__) +# include #elif defined(BOOST_HAS_PTHREADS) # include #else diff --git a/include/boost/detail/lwm_linux.hpp b/include/boost/detail/lwm_linux.hpp index c2ef69a..f502d60 100644 --- a/include/boost/detail/lwm_linux.hpp +++ b/include/boost/detail/lwm_linux.hpp @@ -17,6 +17,7 @@ // #include +#include namespace boost { @@ -60,7 +61,7 @@ public: while( !atomic_dec_and_test(&m_.a_) ) { atomic_inc(&m_.a_); - // sched_yield(); + sched_yield(); } } From 9f295cbb48b76d2464c40adc5b1478d4351e4e69 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 16 Feb 2002 16:09:08 +0000 Subject: [PATCH 076/133] Threaded test added. [SVN r12837] --- shared_ptr_mt_test.cpp | 161 +++++++++++++++++++++++++++++++++++++ shared_ptr_test.cpp | 2 +- shared_ptr_timing_test.cpp | 18 +++++ 3 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 shared_ptr_mt_test.cpp diff --git a/shared_ptr_mt_test.cpp b/shared_ptr_mt_test.cpp new file mode 100644 index 0000000..ac1dac1 --- /dev/null +++ b/shared_ptr_mt_test.cpp @@ -0,0 +1,161 @@ +#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_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 + +#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 + +int main() +{ + std::puts(title); + + boost::shared_ptr pi(new int); + + 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); + } +} diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp index 5039e65..0e4e86b 100644 --- a/shared_ptr_test.cpp +++ b/shared_ptr_test.cpp @@ -8,7 +8,7 @@ // // shared_ptr_test.cpp - a test for shared_ptr.hpp and weak_ptr.hpp // -// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// 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. diff --git a/shared_ptr_timing_test.cpp b/shared_ptr_timing_test.cpp index d456eaf..53fa314 100644 --- a/shared_ptr_timing_test.cpp +++ b/shared_ptr_timing_test.cpp @@ -1,3 +1,21 @@ +#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_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 From 6dfe0896e3a5e2345dc55b978338416767915f13 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 16 Feb 2002 16:14:16 +0000 Subject: [PATCH 077/133] Untabified. [SVN r12838] --- shared_ptr_mt_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared_ptr_mt_test.cpp b/shared_ptr_mt_test.cpp index ac1dac1..af48918 100644 --- a/shared_ptr_mt_test.cpp +++ b/shared_ptr_mt_test.cpp @@ -143,9 +143,9 @@ int const m = 16; // threads int main() { - std::puts(title); + std::puts(title); - boost::shared_ptr pi(new int); + boost::shared_ptr pi(new int); pthread_t a[m]; From e6605637f8c22aac4155f83c1fac5de3b49a751d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 16 Feb 2002 18:45:20 +0000 Subject: [PATCH 078/133] BOOST_LWM_WIN32_USE_CRITICAL_SECTION option. [SVN r12842] --- include/boost/detail/lwm_win32.hpp | 59 +++++++++++++++++++++++++++++- shared_ptr_mt_test.cpp | 9 ++++- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/include/boost/detail/lwm_win32.hpp b/include/boost/detail/lwm_win32.hpp index 60388d5..8bcd469 100644 --- a/include/boost/detail/lwm_win32.hpp +++ b/include/boost/detail/lwm_win32.hpp @@ -16,12 +16,18 @@ // warranty, and with no claim as to its suitability for any purpose. // +#ifndef BOOST_LWM_WIN32_USE_CRITICAL_SECTION +# include +#endif + namespace boost { namespace detail { +#ifndef BOOST_LWM_WIN32_USE_CRITICAL_SECTION + // avoid including extern "C" __declspec(dllimport) long __stdcall InterlockedExchange(long volatile *, long); @@ -67,13 +73,64 @@ public: // Note: adding a Sleep(0) here will make // the mutex more fair and will increase the overall - // performance of the application substantially in + // performance of some applications substantially in // high contention situations, but will penalize the // low contention / single thread case up to 5x } }; }; +#else + +class lightweight_mutex +{ +private: + + CRITICAL_SECTION cs_; + + lightweight_mutex(lightweight_mutex const &); + lightweight_mutex & operator=(lightweight_mutex const &); + +public: + + lightweight_mutex() + { + ::InitializeCriticalSection(&cs_); + } + + ~lightweight_mutex() + { + ::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) + { + ::EnterCriticalSection(&m_.cs_); + } + + ~scoped_lock() + { + ::LeaveCriticalSection(&m_.cs_); + } + }; +}; + +#endif + } // namespace detail } // namespace boost diff --git a/shared_ptr_mt_test.cpp b/shared_ptr_mt_test.cpp index af48918..2511716 100644 --- a/shared_ptr_mt_test.cpp +++ b/shared_ptr_mt_test.cpp @@ -19,6 +19,9 @@ #include #include +#define BOOST_INCLUDE_MAIN +#include + #include #include #include @@ -141,11 +144,11 @@ void test(boost::shared_ptr const & pi) int const m = 16; // threads -int main() +int test_main( int, char ** ) { std::puts(title); - boost::shared_ptr pi(new int); + boost::shared_ptr pi(new int(42)); pthread_t a[m]; @@ -158,4 +161,6 @@ int main() { pthread_join(a[i], 0); } + + return 0; } From 7b53c0040c0b73cc6cd4dd4b14f9d2c1fd77c222 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 18 Feb 2002 12:39:32 +0000 Subject: [PATCH 079/133] More output. [SVN r12852] --- shared_ptr_mt_test.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/shared_ptr_mt_test.cpp b/shared_ptr_mt_test.cpp index 2511716..831be86 100644 --- a/shared_ptr_mt_test.cpp +++ b/shared_ptr_mt_test.cpp @@ -27,6 +27,7 @@ #include #include +#include // 'portable' thread framework @@ -40,7 +41,7 @@ public: #if !defined(BOOST_HAS_PTHREADS) && defined(BOOST_HAS_WINTHREADS) -char const * title = "Using Windows threads."; +char const * title = "Using Windows threads"; #include #include @@ -79,7 +80,7 @@ int pthread_join(pthread_t thread, void ** /*value_ptr*/) #else -char const * title = "Using POSIX threads."; +char const * title = "Using POSIX threads"; #include @@ -146,10 +147,12 @@ int const m = 16; // threads int test_main( int, char ** ) { - std::puts(title); + std::printf("%s: %d threads, %d iterations, ", title, 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) @@ -162,5 +165,9 @@ int test_main( int, char ** ) pthread_join(a[i], 0); } + t = std::clock() - t; + + std::printf("%.4f seconds.\n", static_cast(t) / CLOCKS_PER_SEC); + return 0; } From aa98e2b37ee1b0a4c4470816cf0817056db66a9d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 27 Feb 2002 16:35:15 +0000 Subject: [PATCH 080/133] Added lwm_irix.hpp (contributed by Dan Gohman) [SVN r12955] --- include/boost/detail/lightweight_mutex.hpp | 2 + include/boost/detail/lwm_irix.hpp | 78 ++++++++++++++++++++++ include/boost/detail/lwm_win32.hpp | 57 ---------------- 3 files changed, 80 insertions(+), 57 deletions(-) create mode 100644 include/boost/detail/lwm_irix.hpp diff --git a/include/boost/detail/lightweight_mutex.hpp b/include/boost/detail/lightweight_mutex.hpp index d4ef1c1..69a3a6c 100644 --- a/include/boost/detail/lightweight_mutex.hpp +++ b/include/boost/detail/lightweight_mutex.hpp @@ -40,6 +40,8 @@ # include #elif defined(linux) || defined(__linux) || defined(__linux__) # include +#elif defined(__sgi) +# include #elif defined(BOOST_HAS_PTHREADS) # include #else 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_win32.hpp b/include/boost/detail/lwm_win32.hpp index 8bcd469..3e79198 100644 --- a/include/boost/detail/lwm_win32.hpp +++ b/include/boost/detail/lwm_win32.hpp @@ -16,18 +16,12 @@ // warranty, and with no claim as to its suitability for any purpose. // -#ifndef BOOST_LWM_WIN32_USE_CRITICAL_SECTION -# include -#endif - namespace boost { namespace detail { -#ifndef BOOST_LWM_WIN32_USE_CRITICAL_SECTION - // avoid including extern "C" __declspec(dllimport) long __stdcall InterlockedExchange(long volatile *, long); @@ -80,57 +74,6 @@ public: }; }; -#else - -class lightweight_mutex -{ -private: - - CRITICAL_SECTION cs_; - - lightweight_mutex(lightweight_mutex const &); - lightweight_mutex & operator=(lightweight_mutex const &); - -public: - - lightweight_mutex() - { - ::InitializeCriticalSection(&cs_); - } - - ~lightweight_mutex() - { - ::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) - { - ::EnterCriticalSection(&m_.cs_); - } - - ~scoped_lock() - { - ::LeaveCriticalSection(&m_.cs_); - } - }; -}; - -#endif - } // namespace detail } // namespace boost From 3e0233a26cd4f920ad4482ce53651ab7790f67b6 Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Wed, 27 Feb 2002 17:03:30 +0000 Subject: [PATCH 081/133] Minor text updates in history section. [SVN r12956] --- smart_ptr.htm | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/smart_ptr.htm b/smart_ptr.htm index ce7e38e..1e045f1 100644 --- a/smart_ptr.htm +++ b/smart_ptr.htm @@ -138,15 +138,13 @@ 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.

    +

    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

    +

    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. See the -revision history in smart_ptr.hpp -for the specific changes made as a result of their constructive criticism.

    +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 From 8e604a9da9f7e4c90c14a532f72aa47fddd6e349 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 1 Mar 2002 16:17:08 +0000 Subject: [PATCH 082/133] Disabled the linux-specific versions since using kernel headers is problematic. #define BOOST_USE_ASM_ATOMIC_H to get them back. [SVN r12995] --- include/boost/detail/atomic_count.hpp | 17 +++++++---------- include/boost/detail/atomic_count_linux.hpp | 8 +++++++- include/boost/detail/lightweight_mutex.hpp | 6 +++++- include/boost/detail/lwm_linux.hpp | 10 ++++++++++ 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/include/boost/detail/atomic_count.hpp b/include/boost/detail/atomic_count.hpp index 6486755..d97fafa 100644 --- a/include/boost/detail/atomic_count.hpp +++ b/include/boost/detail/atomic_count.hpp @@ -72,6 +72,8 @@ // 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 @@ -90,17 +92,12 @@ typedef long atomic_count; } #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) - -#include - -#elif defined(linux) || defined(__linux) || defined(__linux__) - -#include - +# include +//#elif defined(linux) || defined(__linux) || defined(__linux__) +#elif defined(BOOST_USE_ASM_ATOMIC_H) +# include #elif defined(BOOST_HAS_PTHREADS) - -#include - +# include #else // #warning Unrecognized platform, detail::atomic_count will not be thread safe diff --git a/include/boost/detail/atomic_count_linux.hpp b/include/boost/detail/atomic_count_linux.hpp index 8fd5346..1a69cec 100644 --- a/include/boost/detail/atomic_count_linux.hpp +++ b/include/boost/detail/atomic_count_linux.hpp @@ -13,7 +13,13 @@ // // -// On Linux, atomic.h is usually located in /usr/include/asm +// 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 diff --git a/include/boost/detail/lightweight_mutex.hpp b/include/boost/detail/lightweight_mutex.hpp index 69a3a6c..d199114 100644 --- a/include/boost/detail/lightweight_mutex.hpp +++ b/include/boost/detail/lightweight_mutex.hpp @@ -31,6 +31,9 @@ // * 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 @@ -38,7 +41,8 @@ # include #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) # include -#elif defined(linux) || defined(__linux) || defined(__linux__) +//#elif defined(linux) || defined(__linux) || defined(__linux__) +#elif defined(BOOST_USE_ASM_ATOMIC_H) # include #elif defined(__sgi) # include diff --git a/include/boost/detail/lwm_linux.hpp b/include/boost/detail/lwm_linux.hpp index f502d60..c4b3b1d 100644 --- a/include/boost/detail/lwm_linux.hpp +++ b/include/boost/detail/lwm_linux.hpp @@ -16,6 +16,16 @@ // 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 From c17f8c36c12246d0beb0ddee4742a898dd74907c Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 8 Mar 2002 16:56:16 +0000 Subject: [PATCH 083/133] weak_ptr::expired() added; weak_ptr documentation updated. [SVN r13141] --- include/boost/weak_ptr.hpp | 7 +- shared_ptr.htm | 4 +- weak_ptr.htm | 416 ++++++++++++++++++++----------------- 3 files changed, 232 insertions(+), 195 deletions(-) diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index 9e9f1a2..33d762d 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -97,7 +97,7 @@ public: T * get() const // never throws; unsafe in multithreaded programs! { - return use_count() == 0? 0: px; + return pn.use_count() == 0? 0: px; } long use_count() const // never throws @@ -105,6 +105,11 @@ public: 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); diff --git a/shared_ptr.htm b/shared_ptr.htm index 8dbd3a1..49649e2 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -297,7 +297,7 @@ q = p;

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

    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.

    @@ -343,7 +343,7 @@ q = p;
  • Otherwise, a default-constructed shared_ptr<T> object.
  • Throws: std::bad_alloc.

    -

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

    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()))

    diff --git a/weak_ptr.htm b/weak_ptr.htm index 9ef44d4..6c1d5dd 100644 --- a/weak_ptr.htm +++ b/weak_ptr.htm @@ -1,35 +1,25 @@ - - - - -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.

    - -

    Synopsis

    - -
    namespace boost {
    +	
    +		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.

    +

    Synopsis

    +
    namespace boost {
     
       template<typename T> class weak_ptr {
     
    @@ -48,12 +38,10 @@ pointed to. T must meet the smart pointer
           template<typename Y> weak_ptr & operator=(shared_ptr<Y> const & r); // never throws
     
           void reset();
    -
    -      T & operator*() const; // never throws
    -      T * operator->() const; // never throws
    -      T * get() const; // never throws
    +      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
       };
    @@ -67,174 +55,218 @@ pointed to. T must meet the smart pointer
     
       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
    +
       template<typename T, typename U>
    -    weak_ptr<T> shared_static_cast(weak_ptr<U> const & r); // never throws
    +    weak_ptr<T> shared_static_cast(weak_ptr<U> const & r); // never throws
       template<typename T, typename U>
    -    weak_ptr<T> shared_dynamic_cast(weak_ptr<U> const & r);
    +    weak_ptr<T> shared_dynamic_cast(weak_ptr<U> const & r);
       template<typename T, typename U>
    -    weak_ptr<T> shared_polymorphic_cast(weak_ptr<U> const & r);
    +    weak_ptr<T> shared_polymorphic_cast(weak_ptr<U> const & r);
       template<typename T, typename U>
    -    weak_ptr<T> shared_polymorphic_downcast(weak_ptr<U> const & r); // never throws
    +    weak_ptr<T> shared_polymorphic_downcast(weak_ptr<U> const & r); // never throws
     
    -}
    - -

    Members

    - -

    element_type

    -
    typedef T element_type;
    -

    Provides the type of the stored pointer.

    - -

    constructors

    - -
    explicit weak_ptr();
    -

    Constructs a weak_ptr, with 0 as its stored pointer. -The only exception which may be thrown by this constructor is std::bad_alloc. -If an exception is thrown, the constructor has no effect.

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

    Constructs a weak_ptr, as if by storing a copy of the pointer stored in r. -Afterwards, 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
    +}
    +
    +

    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
    -

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

    - -

    destructor

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

    Destroys this weak_ptr but has no effect on the object its stored pointer points to. -T need not be a complete type. -See the smart pointer common requirements.

    - -

    assignment

    - -
    weak_ptr & operator=(weak_ptr 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
    -

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

    - -

    reset

    - -
    void reset();
    -

    Constructs a new weak_ptr as described above, -then replaces this weak_ptr with the new one, destroying the replaced object. -The only exception which may be thrown is std::bad_alloc. If -an exception is thrown, the reset has no effect.

    - -

    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. -Note that the stored pointer becomes 0 if all shared_ptr objects for that -pointer are destroyed.

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

    Returns the stored pointer. -Behavior is undefined if the stored pointer is 0. -Note that the stored pointer becomes 0 if all shared_ptr objects for that -pointer are destroyed.

    - -

    get

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

    Returns the stored pointer. -Note that the stored pointer becomes 0 if all shared_ptr objects for that -pointer are destroyed. -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_ptr 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 weak_ptr 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 get should be used for -production code.

    - -

    swap

    -
    void swap(weak_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, typename U>
    +		
    +

    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
    -template<typename T>
    +  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
    -

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

    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
    -

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

    - -

    shared_static_cast

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

    Perform a static_cast on the stored pointer, returning another weak_ptr. -The resulting smart pointer will share its use count with the original pointer.

    - -

    shared_dynamic_cast

    -
    template<typename T, typename U>
    -  weak_ptr<T> shared_dynamic_cast(weak_ptr<U> const & r);
    -

    Perform a dynamic_cast on the stored pointer, returning another weak_ptr. -The resulting smart pointer will share its use count with the original pointer unless the result of the -cast is 0. The only exception which may be thrown is std::bad_alloc, which may be thrown during the -construction of the new weak_ptr if the result of the cast is 0. If an exception is thrown, the -cast has no effect.

    - -

    shared_polymorphic_cast

    -
    template<typename T, typename U>
    -  weak_ptr<T> shared_polymorphic_cast(weak_ptr<U> const & r);
    -

    Perform a polymorphic_cast on the stored pointer, -returning another weak_ptr. -The resulting smart pointer will share its use count with the original pointer. -The only exception which may be thrown is std::bad_cast, if the pointer type can not be converted. -If an exception is thrown, the cast has no effect.

    - -

    shared_polymorphic_downcast

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

    Perform a polymorphic_downcast on the stored pointer, -returning another weak_ptr. -The resulting smart pointer will share its use count with the original pointer.

    - -
    - -

    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.

    - - - +
    +

    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.

    +
    +

    shared_static_cast

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

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

    +

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

    +

    Throws: nothing.

    +
    +

    shared_dynamic_cast

    +
    template<typename T, typename U>
    +  weak_ptr<T> shared_dynamic_cast(weak_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 weak_ptr<T> object that stores a copy of + it and shares ownership with r; +
    • + Otherwise, a default-constructed weak_ptr<T> object.
    +

    Throws: std::bad_alloc.

    +

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

    +
    +

    shared_polymorphic_cast

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

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

    +

    Returns: A weak_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>
    +  weak_ptr<T> shared_polymorphic_downcast(weak_ptr<U> const & r); // never throws
    +
    +

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

    +

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

    +

    Throws: nothing.

    +
    +
    +

    Revised + 8 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.

    + + From 72f83165e025fa0a688be66fc89c7a09a334e6ee Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 12 Mar 2002 14:02:38 +0000 Subject: [PATCH 084/133] Removed casts as unsafe. [SVN r13179] --- include/boost/weak_ptr.hpp | 44 -------------------------------------- shared_ptr_test.cpp | 2 +- 2 files changed, 1 insertion(+), 45 deletions(-) diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index 33d762d..356ab60 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -51,29 +51,6 @@ public: { } - template - weak_ptr(weak_ptr const & r, detail::static_cast_tag): px(static_cast(r.px)), pn(r.pn) - { - } - - template - weak_ptr(weak_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::weak_count(); - } - } - - template - weak_ptr(weak_ptr const & r, detail::polymorphic_cast_tag): px(dynamic_cast(r.px)), pn(r.pn) - { - if (px == 0) - { - throw std::bad_cast(); - } - } - template weak_ptr & operator=(weak_ptr const & r) // never throws { @@ -187,27 +164,6 @@ template shared_ptr make_shared(weak_ptr const & r) // never thro } } -template weak_ptr shared_static_cast(weak_ptr const & r) -{ - return weak_ptr(r, detail::static_cast_tag()); -} - -template weak_ptr shared_dynamic_cast(weak_ptr const & r) -{ - return weak_ptr(r, detail::dynamic_cast_tag()); -} - -template weak_ptr shared_polymorphic_cast(weak_ptr const & r) -{ - return weak_ptr(r, detail::polymorphic_cast_tag()); -} - -template weak_ptr shared_polymorphic_downcast(weak_ptr const & r) -{ - BOOST_ASSERT(dynamic_cast(r.get()) == r.get()); - return shared_static_cast(r); -} - } // namespace boost #ifdef BOOST_MSVC diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp index 0e4e86b..7b1b960 100644 --- a/shared_ptr_test.cpp +++ b/shared_ptr_test.cpp @@ -244,7 +244,7 @@ int test_main(int, char * []) test_is_nonzero(boost::make_shared(wp2)); } - weak_ptr wp3 = shared_dynamic_cast(wp2); + weak_ptr wp3 = shared_dynamic_cast(boost::make_shared(wp2)); BOOST_TEST(wp3.use_count() == 1); BOOST_TEST(wp3.get() != 0); From 220f35a0f15f43c9afff6420b9f7fb71c7a6f3c6 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 12 Mar 2002 14:39:22 +0000 Subject: [PATCH 085/133] Casts removed as unsafe, added intro paragraph about make_shared. [SVN r13180] --- weak_ptr.htm | 99 +++++++++++++++++++--------------------------------- 1 file changed, 35 insertions(+), 64 deletions(-) diff --git a/weak_ptr.htm b/weak_ptr.htm index 6c1d5dd..72104fb 100644 --- a/weak_ptr.htm +++ b/weak_ptr.htm @@ -18,6 +18,40 @@

    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 {
     
    @@ -58,15 +92,6 @@
       template<typename T>
         shared_ptr<T> make_shared(weak_ptr<T> const & r); // never throws
     
    -  template<typename T, typename U>
    -    weak_ptr<T> shared_static_cast(weak_ptr<U> const & r); // never throws
    -  template<typename T, typename U>
    -    weak_ptr<T> shared_dynamic_cast(weak_ptr<U> const & r);
    -  template<typename T, typename U>
    -    weak_ptr<T> shared_polymorphic_cast(weak_ptr<U> const & r);
    -  template<typename T, typename U>
    -    weak_ptr<T> shared_polymorphic_downcast(weak_ptr<U> const & r); // never throws
    -
     }
     

    Members

    @@ -206,62 +231,8 @@ template<typename T, typename U>

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

    Throws: nothing.

    -

    shared_static_cast

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

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

    -

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

    -

    Throws: nothing.

    -
    -

    shared_dynamic_cast

    -
    template<typename T, typename U>
    -  weak_ptr<T> shared_dynamic_cast(weak_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 weak_ptr<T> object that stores a copy of - it and shares ownership with r; -
    • - Otherwise, a default-constructed weak_ptr<T> object.
    -

    Throws: std::bad_alloc.

    -

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

    -
    -

    shared_polymorphic_cast

    -
    template<typename T, typename U>
    -  weak_ptr<T> shared_polymorphic_cast(weak_ptr<U> const & r);
    -
    -

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

    -

    Returns: A weak_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>
    -  weak_ptr<T> shared_polymorphic_downcast(weak_ptr<U> const & r); // never throws
    -
    -

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

    -

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

    -

    Throws: nothing.

    -

    -

    Revised - 8 March 2002

    +

    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 From b89945d36a7ba6fe88deac7ac0a11c1e75501fef Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 15 Mar 2002 22:00:10 +0000 Subject: [PATCH 086/133] Added winapi.hpp and a CRITICAL_SECTION lightweight_mutex variant. [SVN r13211] --- include/boost/detail/atomic_count.hpp | 8 +- .../boost/detail/atomic_count_pthreads.hpp | 4 +- include/boost/detail/atomic_count_win32.hpp | 14 +--- include/boost/detail/lightweight_mutex.hpp | 18 ++++- include/boost/detail/lwm_win32.hpp | 14 ++-- include/boost/detail/lwm_win32_cs.hpp | 78 +++++++++++++++++++ include/boost/detail/winapi.hpp | 75 ++++++++++++++++++ 7 files changed, 185 insertions(+), 26 deletions(-) create mode 100644 include/boost/detail/lwm_win32_cs.hpp create mode 100644 include/boost/detail/winapi.hpp diff --git a/include/boost/detail/atomic_count.hpp b/include/boost/detail/atomic_count.hpp index d97fafa..2adb57e 100644 --- a/include/boost/detail/atomic_count.hpp +++ b/include/boost/detail/atomic_count.hpp @@ -91,12 +91,14 @@ typedef long atomic_count; } -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) -# include -//#elif defined(linux) || defined(__linux) || defined(__linux__) #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 diff --git a/include/boost/detail/atomic_count_pthreads.hpp b/include/boost/detail/atomic_count_pthreads.hpp index eb1dd97..0f8c663 100644 --- a/include/boost/detail/atomic_count_pthreads.hpp +++ b/include/boost/detail/atomic_count_pthreads.hpp @@ -19,11 +19,9 @@ // inefficiencies. Example: a class with two atomic_count members // can get away with a single mutex. // -// Define a macro so that users can detect the situation and optimize. +// Users can detect this situation by checking BOOST_AC_USE_PTHREADS. // -#define BOOST_ATOMIC_COUNT_USES_PTHREADS - namespace boost { diff --git a/include/boost/detail/atomic_count_win32.hpp b/include/boost/detail/atomic_count_win32.hpp index 163a26d..0482757 100644 --- a/include/boost/detail/atomic_count_win32.hpp +++ b/include/boost/detail/atomic_count_win32.hpp @@ -16,20 +16,14 @@ // warranty, and with no claim as to its suitability for any purpose. // +#include + namespace boost { namespace detail { -// Avoid #including - -namespace win32 -{ -extern "C" __declspec(dllimport) long __stdcall InterlockedIncrement(long volatile *); -extern "C" __declspec(dllimport) long __stdcall InterlockedDecrement(long volatile *); -} - class atomic_count { public: @@ -40,12 +34,12 @@ public: long operator++() { - return win32::InterlockedIncrement(&value_); + return winapi::InterlockedIncrement(&value_); } long operator--() { - return win32::InterlockedDecrement(&value_); + return winapi::InterlockedDecrement(&value_); } operator long() const diff --git a/include/boost/detail/lightweight_mutex.hpp b/include/boost/detail/lightweight_mutex.hpp index d199114..6a74397 100644 --- a/include/boost/detail/lightweight_mutex.hpp +++ b/include/boost/detail/lightweight_mutex.hpp @@ -37,16 +37,28 @@ #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(WIN32) || defined(_WIN32) || defined(__WIN32__) -# include -//#elif defined(linux) || defined(__linux) || defined(__linux__) #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 diff --git a/include/boost/detail/lwm_win32.hpp b/include/boost/detail/lwm_win32.hpp index 3e79198..a54aefc 100644 --- a/include/boost/detail/lwm_win32.hpp +++ b/include/boost/detail/lwm_win32.hpp @@ -16,17 +16,14 @@ // warranty, and with no claim as to its suitability for any purpose. // +#include + namespace boost { namespace detail { -// avoid including - -extern "C" __declspec(dllimport) long __stdcall InterlockedExchange(long volatile *, long); -extern "C" __declspec(dllimport) void __stdcall Sleep(unsigned long); - class lightweight_mutex { private: @@ -58,12 +55,15 @@ public: explicit scoped_lock(lightweight_mutex & m): m_(m) { - while( InterlockedExchange(&m_.l_, 1) ) Sleep(0); + while( winapi::InterlockedExchange(&m_.l_, 1) ) + { + winapi::Sleep(0); + } } ~scoped_lock() { - InterlockedExchange(&m_.l_, 0); + winapi::InterlockedExchange(&m_.l_, 0); // Note: adding a Sleep(0) here will make // the mutex more fair and will increase the overall 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/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 From fb5b1a20d2b55b76c2a8e9ad6c568f5496eefcfc Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 15 Mar 2002 22:03:56 +0000 Subject: [PATCH 087/133] Small modifications. [SVN r13212] --- shared_ptr_mt_test.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/shared_ptr_mt_test.cpp b/shared_ptr_mt_test.cpp index 831be86..489aa7c 100644 --- a/shared_ptr_mt_test.cpp +++ b/shared_ptr_mt_test.cpp @@ -84,7 +84,7 @@ char const * title = "Using POSIX threads"; #include -extern "C" void* common_thread_routine(void * pv) +extern "C" void * common_thread_routine(void * pv) { abstract_thread * pt = static_cast(pv); pt->run(); @@ -145,9 +145,17 @@ void test(boost::shared_ptr const & 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: %d threads, %d iterations, ", title, m, n); + std::printf("%s: %s, %d threads, %d iterations: ", title, implementation, m, n); boost::shared_ptr pi(new int(42)); @@ -167,7 +175,7 @@ int test_main( int, char ** ) t = std::clock() - t; - std::printf("%.4f seconds.\n", static_cast(t) / CLOCKS_PER_SEC); + std::printf("\n\n%.3f seconds.\n", static_cast(t) / CLOCKS_PER_SEC); return 0; } From 9eb1ba7e9fcc68ed83f373d7669ef9252626aef5 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Sat, 6 Apr 2002 21:44:37 +0000 Subject: [PATCH 088/133] test_main args must be *[] not ** for new rev of test tools [SVN r13381] --- smart_ptr_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smart_ptr_test.cpp b/smart_ptr_test.cpp index baee93d..79edf7e 100644 --- a/smart_ptr_test.cpp +++ b/smart_ptr_test.cpp @@ -88,7 +88,7 @@ Incomplete * check_incomplete( shared_ptr& incomplete, // This isn't a very systematic test; it just hits some of the basics. -int test_main( int, char ** ) { +int test_main( int, char *[] ) { BOOST_TEST( UDT_use_count == 0 ); // reality check From 513752eee50e714fc7d30badd572847f1ac69896 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 10 Apr 2002 14:12:12 +0000 Subject: [PATCH 089/133] Worked around an MSVC 6 bug (Markus Schoepflin) [SVN r13430] --- include/boost/shared_ptr.hpp | 6 +++++- include/boost/weak_ptr.hpp | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index 0c00e9a..ad013d3 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -140,7 +140,9 @@ public: { } -#endif +#endif + +#if !defined(BOOST_MSVC) || (BOOST_MSVC > 1200) template shared_ptr & operator=(shared_ptr const & r) // never throws @@ -150,6 +152,8 @@ public: return *this; } +#endif + #ifndef BOOST_NO_AUTO_PTR template diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index 356ab60..01c248c 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -51,6 +51,8 @@ public: { } +#if !defined(BOOST_MSVC) || (BOOST_MSVC > 1200) + template weak_ptr & operator=(weak_ptr const & r) // never throws { @@ -67,6 +69,8 @@ public: return *this; } +#endif + void reset() { this_type().swap(*this); From 9b800d4f84b05d51401e66155044ba3a7b39bf35 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 10 Apr 2002 16:04:53 +0000 Subject: [PATCH 090/133] Added more mem_fn, shared_ptr tests. [SVN r13432] --- shared_ptr_assign_fail.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 shared_ptr_assign_fail.cpp 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; +} From fbc902831395559dadc40cd3b1f549a75dfe3a79 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 19 Apr 2002 19:34:16 +0000 Subject: [PATCH 091/133] intrusive_ptr.hpp added (still experimental) [SVN r13526] --- include/boost/detail/shared_count.hpp | 23 ++- include/boost/intrusive_ptr.hpp | 201 ++++++++++++++++++++++++++ include/boost/shared_ptr.hpp | 6 + 3 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 include/boost/intrusive_ptr.hpp diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 9dfed4f..22a1e09 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -41,9 +41,6 @@ public: } }; -namespace detail -{ - class counted_base { public: @@ -77,7 +74,7 @@ public: #ifdef BOOST_HAS_THREADS lightweight_mutex::scoped_lock lock(mtx_); #endif - if(use_count_ == 0) throw use_count_is_zero(); + if(use_count_ == 0 && weak_count_ != 0) throw use_count_is_zero(); ++use_count_; ++weak_count_; } @@ -161,6 +158,19 @@ private: void (*self_deleter_) (counted_base *); }; +inline void intrusive_ptr_add_ref(counted_base * p) +{ + if(p != 0) p->add_ref(); +} + +inline void intrusive_ptr_release(counted_base * p) +{ + if(p != 0) p->release(); +} + +namespace detail +{ + template class counted_base_impl: public counted_base { private: @@ -202,6 +212,11 @@ public: { } + explicit shared_count(counted_base * pi): pi_(pi) // never throws + { + pi_->add_ref(); + } + template shared_count(P p, D d): pi_(0) { try diff --git a/include/boost/intrusive_ptr.hpp b/include/boost/intrusive_ptr.hpp new file mode 100644 index 0000000..1d5349a --- /dev/null +++ b/include/boost/intrusive_ptr.hpp @@ -0,0 +1,201 @@ +#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); +// (note: p may be 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) + { + intrusive_ptr_add_ref(p_); + } + + ~intrusive_ptr() + { + intrusive_ptr_release(p_); + } + +#ifdef BOOST_MSVC6_MEMBER_TEMPLATES + + template intrusive_ptr(intrusive_ptr const & rhs): p_(rhs.get()) + { + intrusive_ptr_add_ref(p_); + } + +#endif + + intrusive_ptr(intrusive_ptr const & rhs): p_(rhs.p_) + { + 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/shared_ptr.hpp b/include/boost/shared_ptr.hpp index ad013d3..6cb187d 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -68,6 +68,7 @@ template<> struct shared_ptr_traits // template class weak_ptr; +template class intrusive_ptr; template class shared_ptr { @@ -110,6 +111,11 @@ public: { } + 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) { From 4c5e355a0b0328f64535d6f19ab5b0f68c6634a4 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 22 Apr 2002 09:37:08 +0000 Subject: [PATCH 092/133] Bugfixes. [SVN r13541] --- include/boost/detail/shared_count.hpp | 16 ++++++++++------ include/boost/intrusive_ptr.hpp | 2 +- include/boost/weak_ptr.hpp | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 22a1e09..51df052 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -43,6 +43,10 @@ public: class counted_base { +private: + + typedef detail::lightweight_mutex mutex_type; + public: // pre: initial_use_count <= initial_weak_count @@ -72,7 +76,7 @@ public: void add_ref() { #ifdef BOOST_HAS_THREADS - lightweight_mutex::scoped_lock lock(mtx_); + mutex_type::scoped_lock lock(mtx_); #endif if(use_count_ == 0 && weak_count_ != 0) throw use_count_is_zero(); ++use_count_; @@ -86,7 +90,7 @@ public: { #ifdef BOOST_HAS_THREADS - lightweight_mutex::scoped_lock lock(mtx_); + mutex_type::scoped_lock lock(mtx_); #endif new_use_count = --use_count_; new_weak_count = --weak_count_; @@ -108,7 +112,7 @@ public: void weak_add_ref() // nothrow { #ifdef BOOST_HAS_THREADS - lightweight_mutex::scoped_lock lock(mtx_); + mutex_type::scoped_lock lock(mtx_); #endif ++weak_count_; } @@ -119,7 +123,7 @@ public: { #ifdef BOOST_HAS_THREADS - lightweight_mutex::scoped_lock lock(mtx_); + mutex_type::scoped_lock lock(mtx_); #endif new_weak_count = --weak_count_; } @@ -133,7 +137,7 @@ public: long use_count() const // nothrow { #ifdef BOOST_HAS_THREADS - lightweight_mutex::scoped_lock lock(mtx_); + mutex_type::scoped_lock lock(mtx_); #endif return use_count_; } @@ -153,7 +157,7 @@ private: long use_count_; long weak_count_; #ifdef BOOST_HAS_THREADS - mutable lightweight_mutex mtx_; + mutable mutex_type mtx_; #endif void (*self_deleter_) (counted_base *); }; diff --git a/include/boost/intrusive_ptr.hpp b/include/boost/intrusive_ptr.hpp index 1d5349a..87dbece 100644 --- a/include/boost/intrusive_ptr.hpp +++ b/include/boost/intrusive_ptr.hpp @@ -17,7 +17,7 @@ #ifdef BOOST_MSVC // moved here to work around VC++ compiler crash # pragma warning(push) # pragma warning(disable:4284) // odd return type for operator-> -#endif +#endif #include // std::less diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index 01c248c..e04b4f1 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -19,7 +19,7 @@ #ifdef BOOST_MSVC // moved here to work around VC++ compiler crash # pragma warning(push) # pragma warning(disable:4284) // odd return type for operator-> -#endif +#endif namespace boost { From 110c0021e2dfa1685ae9b0df10b7a6f7d570b222 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 22 Apr 2002 18:01:19 +0000 Subject: [PATCH 093/133] counted_base default constructor added [SVN r13542] --- include/boost/detail/shared_count.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 51df052..225a56d 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -49,6 +49,11 @@ private: 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): From 11eacab70eb282ca1b7591f39fd16c0c6de7b943 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 23 Apr 2002 14:56:42 +0000 Subject: [PATCH 094/133] Made shared_ptr::share_ptr(Y * p) a member template. [SVN r13551] --- include/boost/shared_ptr.hpp | 14 ++++++++------ shared_ptr_mt_test.cpp | 2 +- shared_ptr_test.cpp | 2 +- shared_ptr_timing_test.cpp | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index 6cb187d..cf43a1e 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -75,7 +75,7 @@ template class shared_ptr private: // Borland 5.5.1 specific workarounds - typedef checked_deleter deleter; +// typedef checked_deleter deleter; typedef shared_ptr this_type; public: @@ -86,7 +86,8 @@ public: { } - explicit shared_ptr(T * p): px(p), pn(p, deleter()) // requires complete type + template + explicit shared_ptr(Y * p): px(p), pn(p, checked_deleter()) // Y must be complete { } @@ -96,13 +97,14 @@ public: // shared_ptr will release p by calling d(p) // - template shared_ptr(T * p, D d): px(p), pn(p, d) + template shared_ptr(Y * p, D d): px(p), pn(p, d) { } // generated copy constructor, assignment, destructor are fine - explicit shared_ptr(weak_ptr const & r): px(r.px), pn(r.pn) // may throw + template + explicit shared_ptr(weak_ptr const & r): px(r.px), pn(r.pn) // may throw { } @@ -176,13 +178,13 @@ public: this_type().swap(*this); } - void reset(T * p) // requires complete type + 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(T * p, D d) + template void reset(Y * p, D d) { this_type(p, d).swap(*this); } diff --git a/shared_ptr_mt_test.cpp b/shared_ptr_mt_test.cpp index 489aa7c..185bd99 100644 --- a/shared_ptr_mt_test.cpp +++ b/shared_ptr_mt_test.cpp @@ -1,4 +1,4 @@ -#if defined(_MSC_VER) && !defined(__ICL) +#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 diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp index 7b1b960..9ef6d3d 100644 --- a/shared_ptr_test.cpp +++ b/shared_ptr_test.cpp @@ -1,4 +1,4 @@ -#if defined(_MSC_VER) && !defined(__ICL) +#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 diff --git a/shared_ptr_timing_test.cpp b/shared_ptr_timing_test.cpp index 53fa314..299261b 100644 --- a/shared_ptr_timing_test.cpp +++ b/shared_ptr_timing_test.cpp @@ -1,4 +1,4 @@ -#if defined(_MSC_VER) && !defined(__ICL) +#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 From 4653c3673b779b0cfcabb39982af561ac07a960b Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 1 May 2002 11:22:22 +0000 Subject: [PATCH 095/133] shared_ptr now autodetects counted_bases; minor test updates; intrusive_ptr no longer calls addref/release for NULL pointers. [SVN r13602] --- include/boost/detail/shared_count.hpp | 13 ++++++--- include/boost/intrusive_ptr.hpp | 11 ++++---- include/boost/shared_ptr.hpp | 2 +- shared_ptr_test.cpp | 38 ++++++++++++++++++++++++--- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 225a56d..63316f4 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -169,12 +169,12 @@ private: inline void intrusive_ptr_add_ref(counted_base * p) { - if(p != 0) p->add_ref(); + p->add_ref(); } inline void intrusive_ptr_release(counted_base * p) { - if(p != 0) p->release(); + p->release(); } namespace detail @@ -215,6 +215,8 @@ private: friend class weak_count; + template shared_count(P, D, counted_base const *); + public: shared_count(): pi_(new counted_base(1, 1)) @@ -226,7 +228,7 @@ public: pi_->add_ref(); } - template shared_count(P p, D d): pi_(0) + template shared_count(P p, D d, void const * = 0): pi_(0) { try { @@ -239,6 +241,11 @@ public: } } + 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 diff --git a/include/boost/intrusive_ptr.hpp b/include/boost/intrusive_ptr.hpp index 87dbece..780fe78 100644 --- a/include/boost/intrusive_ptr.hpp +++ b/include/boost/intrusive_ptr.hpp @@ -33,7 +33,8 @@ namespace boost // // void intrusive_ptr_add_ref(T * p); // void intrusive_ptr_release(T * p); -// (note: p may be 0!) +// +// (p != 0) // // The object is responsible for destroying itself. // @@ -52,26 +53,26 @@ public: intrusive_ptr(T * p): p_(p) { - intrusive_ptr_add_ref(p_); + if(p_ != 0) intrusive_ptr_add_ref(p_); } ~intrusive_ptr() { - intrusive_ptr_release(p_); + if(p_ != 0) intrusive_ptr_release(p_); } #ifdef BOOST_MSVC6_MEMBER_TEMPLATES template intrusive_ptr(intrusive_ptr const & rhs): p_(rhs.get()) { - intrusive_ptr_add_ref(p_); + if(p_ != 0) intrusive_ptr_add_ref(p_); } #endif intrusive_ptr(intrusive_ptr const & rhs): p_(rhs.p_) { - intrusive_ptr_add_ref(p_); + if(p_ != 0) intrusive_ptr_add_ref(p_); } #ifdef BOOST_MSVC6_MEMBER_TEMPLATES diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index cf43a1e..39df95f 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -87,7 +87,7 @@ public: } template - explicit shared_ptr(Y * p): px(p), pn(p, checked_deleter()) // Y must be complete + explicit shared_ptr(Y * p): px(p), pn(p, checked_deleter(), p) // Y must be complete { } diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp index 9ef6d3d..f96dfc6 100644 --- a/shared_ptr_test.cpp +++ b/shared_ptr_test.cpp @@ -40,7 +40,7 @@ struct X std::cout << "X(" << this << ")::X()\n"; } - virtual ~X() + ~X() // virtual destructor deliberately omitted { --cnt; std::cout << "X(" << this << ")::~X()\n"; @@ -96,6 +96,28 @@ void release_object(int * p) 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); @@ -244,7 +266,7 @@ int test_main(int, char * []) test_is_nonzero(boost::make_shared(wp2)); } - weak_ptr wp3 = shared_dynamic_cast(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); @@ -302,7 +324,17 @@ int test_main(int, char * []) BOOST_TEST(b1 == (wp1 < wp5)); BOOST_TEST(b2 == (wp5 < wp1)); - shared_ptr p6(get_object(), release_object); + { + // 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); From 70255d46bb9058a8f976a2d1f06a97b144204b3d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 4 May 2002 14:27:21 +0000 Subject: [PATCH 096/133] Documented templated pointer constructors, revised the intro a bit. [SVN r13665] --- shared_ptr.htm | 95 ++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 53 deletions(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index 49649e2..fc9df88 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -31,12 +31,19 @@ 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.

    + 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. T must meet the smart pointer - common requirements. T may be void, but in that case, - either an explicit delete function must be passed in, or the pointed-to object - must have a trivial destructor.

    + 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 {
     
    @@ -47,11 +54,12 @@
       template<typename T> class shared_ptr {
     
         public:
    +
           typedef T element_type;
     
           shared_ptr ();
    -      explicit shared_ptr (T * p); // requires complete type
    -      template<typename D> shared_ptr(T * p, D d);
    +      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
    @@ -64,8 +72,8 @@
           template<typename Y> shared_ptr & operator=(std::auto_ptr<Y> & r);
     
           void reset ();
    -      void reset (T * p); // requires complete type
    -      template<typename D> void reset(T * p, D d);
    +      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
    @@ -113,13 +121,12 @@
     			

    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.

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

    Requirements: The expression delete p must be well-formed - and must not invoke undefined behavior. +

    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.

    @@ -131,11 +138,12 @@ 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 D> shared_ptr(T * p, D d);
    +
    template<typename Y, typename D> shared_ptr(Y * p, D d);
    -

    Requirements: 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. +

    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.

    @@ -180,10 +188,6 @@ template<typename Y> shared_ptr(shared_ptr<Y> const & r); // nev

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

    Throws: nothing.

    -

    Notes: T need not be a complete type. The guarantee that the - destructor 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_ptr & operator=(shared_ptr const & r); // never throws
    @@ -207,12 +211,11 @@ q = p;
     		

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

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

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

    -

    Notes: Note the implied requirement that T is a complete type.

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

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

    @@ -234,17 +237,13 @@ q = p;

    Returns: the stored pointer.

    Throws: nothing.

    -

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

    unique

    bool unique() const; // never throws

    Returns: use_count() == 1.

    Throws: nothing.

    -

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

    +

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

    use_count

    long use_count() const; // never throws
    @@ -253,9 +252,7 @@ q = p; 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.

    + for debugging and testing purposes, not for production code.

    conversions

    operator implementation-defined-type () const; // never throws
    @@ -264,17 +261,15 @@ q = p; 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.

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

    -

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

    Free Functions

    comparison

    @@ -283,27 +278,22 @@ q = p;

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

    Throws: nothing.

    -

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

    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.

    -

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

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

    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. T need not be a complete type. See the smart - pointer common requirements.

    + associative containers.

    swap

    template<typename T>
    @@ -337,14 +327,13 @@ q = p;
     			

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

    +

    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 @@ -456,8 +445,8 @@ int * p = a.release(); implementation or a linked list implementation, or some other specific implementation. This is not the intent.


    -

    Revised  - 14 February 2002

    +

    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 From ecb0b4478bd4228d4b881fc5e5a128f238ae8940 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 9 May 2002 11:16:29 +0000 Subject: [PATCH 097/133] Typo fixed. [SVN r13770] --- shared_ptr.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index fc9df88..be047d7 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -408,7 +408,7 @@ q = p; 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 use where appropriate to +

    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.

    From 23f68a5657f71b415f2829f1c1d16e694f95e164 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 21 May 2002 16:48:20 +0000 Subject: [PATCH 098/133] =?UTF-8?q?Added=20libstdc++=20v3=20specific=20lig?= =?UTF-8?q?htweight=5Fmutex=20and=20atomic=5Fcount=20(contributed=20by=20L?= =?UTF-8?q?ars=20Gullik=20Bj=C3=B8nnes)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [SVN r13999] --- include/boost/detail/atomic_count.hpp | 2 + include/boost/detail/atomic_count_gcc.hpp | 61 +++++++++++++++++ include/boost/detail/lightweight_mutex.hpp | 10 ++- include/boost/detail/lwm_gcc.hpp | 78 ++++++++++++++++++++++ include/boost/detail/lwm_linux.hpp | 2 +- 5 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 include/boost/detail/atomic_count_gcc.hpp create mode 100644 include/boost/detail/lwm_gcc.hpp diff --git a/include/boost/detail/atomic_count.hpp b/include/boost/detail/atomic_count.hpp index 2adb57e..b34dc85 100644 --- a/include/boost/detail/atomic_count.hpp +++ b/include/boost/detail/atomic_count.hpp @@ -97,6 +97,8 @@ typedef long atomic_count; # include #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) # include +#elif defined(__GLIBCPP__) +# include #elif defined(BOOST_HAS_PTHREADS) # define BOOST_AC_USE_PTHREADS # include diff --git a/include/boost/detail/atomic_count_gcc.hpp b/include/boost/detail/atomic_count_gcc.hpp new file mode 100644 index 0000000..c3d29a8 --- /dev/null +++ b/include/boost/detail/atomic_count_gcc.hpp @@ -0,0 +1,61 @@ +#ifndef BOOST_DETAIL_ATOMIC_COUNT_GCC_HPP_INCLUDED +#define BOOST_DETAIL_ATOMIC_COUNT_GCC_HPP_INCLUDED + +// +// boost/detail/atomic_count_gcc.hpp +// +// atomic_count for GNU libstdc++ v3 +// +// http://gcc.gnu.org/onlinedocs/porting/Thread-safety.html +// +// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2002 Lars Gullik Bjĝnnes +// +// 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) {} + + void operator++() + { + __atomic_add(&value_, 1); + } + + long operator--() + { + return !__exchange_and_add(&value_, -1); + } + + operator long() const + { + return __exchange_and_add(&value_, 0); + } + +private: + + atomic_count(atomic_count const &); + atomic_count & operator=(atomic_count const &); + + _Atomic_word value_; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_ATOMIC_COUNT_GCC_HPP_INCLUDED diff --git a/include/boost/detail/lightweight_mutex.hpp b/include/boost/detail/lightweight_mutex.hpp index 6a74397..b92b576 100644 --- a/include/boost/detail/lightweight_mutex.hpp +++ b/include/boost/detail/lightweight_mutex.hpp @@ -40,10 +40,14 @@ // // 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 +// against the pthreads-based version using shared_ptr_timing_test.cpp and +// shared_ptr_mt_test.cpp. Custom versions are usually not worth the trouble // _unless_ the performance gains are substantial. // +// Be sure to compare against a "real" pthreads library; +// shared_ptr_timing_test.cpp will compile succesfully with a stub do-nothing +// pthreads library, since it doesn't create any threads. +// #ifndef BOOST_HAS_THREADS # include @@ -57,6 +61,8 @@ # include #elif defined(__sgi) # include +#elif defined(__GLIBCPP__) +# include #elif defined(BOOST_HAS_PTHREADS) # define BOOST_LWM_USE_PTHREADS # include diff --git a/include/boost/detail/lwm_gcc.hpp b/include/boost/detail/lwm_gcc.hpp new file mode 100644 index 0000000..bf8a09a --- /dev/null +++ b/include/boost/detail/lwm_gcc.hpp @@ -0,0 +1,78 @@ +#ifndef BOOST_DETAIL_LWM_GCC_HPP_INCLUDED +#define BOOST_DETAIL_LWM_GCC_HPP_INCLUDED + +// +// boost/detail/lwm_gcc.hpp +// +// lightweight_mutex for GNU libstdc++ v3 +// +// http://gcc.gnu.org/onlinedocs/porting/Thread-safety.html +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2002 Lars Gullik Bjĝnnes +// +// 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 + +namespace boost +{ + +namespace detail +{ + +class lightweight_mutex +{ +private: + + _Atomic_word a_; + + lightweight_mutex(lightweight_mutex const &); + lightweight_mutex & operator=(lightweight_mutex const &); + +public: + + lightweight_mutex(): a_(1) + { + } + + class scoped_lock; + friend class scoped_lock; + + class scoped_lock + { + private: + + lightweight_mutex & m_; + + scoped_lock(scoped_lock const &); + scoped_lock & operator=(scoped_lock const &); + + public: + + explicit scoped_lock(lightweight_mutex & m): m_(m) + { + while( !__exchange_and_add(&m_.a_, -1) ) + { + __atomic_add(&m_.a_, 1); + sched_yield(); + } + } + + ~scoped_lock() + { + __atomic_add(&m_.a_, 1); + } + }; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_LWM_GCC_HPP_INCLUDED diff --git a/include/boost/detail/lwm_linux.hpp b/include/boost/detail/lwm_linux.hpp index c4b3b1d..62d8e64 100644 --- a/include/boost/detail/lwm_linux.hpp +++ b/include/boost/detail/lwm_linux.hpp @@ -86,4 +86,4 @@ public: } // namespace boost -#endif // #ifndef BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED +#endif // #ifndef BOOST_DETAIL_LWM_LINUX_HPP_INCLUDED From 951c2b7e833146f20023b0609c67d2689f446f16 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 20 Jun 2002 14:56:10 +0000 Subject: [PATCH 099/133] counted_base is now smaller [SVN r14212] --- include/boost/detail/shared_count.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 63316f4..cc325ea 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -50,14 +50,14 @@ private: public: counted_base(): - use_count_(0), weak_count_(0), self_deleter_(&self_delete) + use_count_(0), weak_count_(0) { } // pre: initial_use_count <= initial_weak_count explicit counted_base(long initial_use_count, long initial_weak_count): - use_count_(initial_use_count), weak_count_(initial_weak_count), self_deleter_(&self_delete) + use_count_(initial_use_count), weak_count_(initial_weak_count) { } @@ -78,6 +78,13 @@ public: { } + // destruct() is called when weak_count_ drops to zero. + + virtual void destruct() // nothrow + { + delete this; + } + void add_ref() { #ifdef BOOST_HAS_THREADS @@ -108,9 +115,7 @@ public: if(new_weak_count == 0) { - // not a direct 'delete this', because the inlined - // release() may use a different heap manager - self_deleter_(this); + destruct(); } } @@ -135,7 +140,7 @@ public: if(new_weak_count == 0) { - self_deleter_(this); + destruct(); } } @@ -152,19 +157,14 @@ private: counted_base(counted_base const &); counted_base & operator= (counted_base const &); - static void self_delete(counted_base * p) - { - delete p; - } - // inv: use_count_ <= weak_count_ long use_count_; long weak_count_; + #ifdef BOOST_HAS_THREADS mutable mutex_type mtx_; #endif - void (*self_deleter_) (counted_base *); }; inline void intrusive_ptr_add_ref(counted_base * p) From a322dc54dcf2c774084325f2cb38789a5c174534 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 20 Jun 2002 15:16:03 +0000 Subject: [PATCH 100/133] Platform-specific spinlocks disabled by default unless BOOST_LWM_USE_SPINLOCK is defined. [SVN r14213] --- include/boost/detail/lightweight_mutex.hpp | 33 ++++++++++++++++------ 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/include/boost/detail/lightweight_mutex.hpp b/include/boost/detail/lightweight_mutex.hpp index b92b576..da9e575 100644 --- a/include/boost/detail/lightweight_mutex.hpp +++ b/include/boost/detail/lightweight_mutex.hpp @@ -15,10 +15,10 @@ // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // -// typedef boost::detail::lightweight_mutex; +// 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 +// boost::detail::lightweight_mutex meets a subset of the Mutex concept +// requirements: http://www.boost.org/libs/thread/doc/mutex_concept.html#Mutex // // * Used by the smart pointer library // * Performance oriented @@ -30,6 +30,23 @@ // lightweight_mutex does not guarantee fairness. // * Never keep a lightweight_mutex locked for long periods. // +// The current implementation can use a pthread_mutex, a CRITICAL_SECTION, +// or a platform-specific spinlock. +// +// You can force a particular implementation by defining BOOST_LWM_USE_PTHREADS, +// BOOST_LWM_USE_CRITICAL_SECTION, or BOOST_LWM_USE_SPINLOCK. +// +// If neither macro has been defined, the default is to use a spinlock on Win32, +// and a pthread_mutex otherwise. +// +// Note that a spinlock is not a general synchronization primitive. In particular, +// it is not guaranteed to be a memory barrier, and it is possible to "livelock" +// if a lower-priority thread has acquired the spinlock but a higher-priority +// thread is spinning trying to acquire the same lock. +// +// For these reasons, spinlocks have been disabled by default except on Windows, +// where a spinlock can be several orders of magnitude faster than a CRITICAL_SECTION. + // Note: lwm_linux.hpp has been disabled by default; see the comments // inside for more info. @@ -37,8 +54,7 @@ #include -// -// Note to implementors: if you write a platform-specific lightweight_mutex +// Note to implementors: if you write a platform-specific spinlock // for a platform that supports pthreads, be sure to test its performance // against the pthreads-based version using shared_ptr_timing_test.cpp and // shared_ptr_mt_test.cpp. Custom versions are usually not worth the trouble @@ -47,11 +63,10 @@ // Be sure to compare against a "real" pthreads library; // shared_ptr_timing_test.cpp will compile succesfully with a stub do-nothing // pthreads library, since it doesn't create any threads. -// #ifndef BOOST_HAS_THREADS # include -#elif defined(BOOST_USE_ASM_ATOMIC_H) +#elif defined(BOOST_LWM_USE_SPINLOCK) && defined(BOOST_USE_ASM_ATOMIC_H) # include #elif defined(BOOST_LWM_USE_CRITICAL_SECTION) # include @@ -59,9 +74,9 @@ # include #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) # include -#elif defined(__sgi) +#elif defined(BOOST_LWM_USE_SPINLOCK) && defined(__sgi) # include -#elif defined(__GLIBCPP__) +#elif defined(BOOST_LWM_USE_SPINLOCK) && defined(__GLIBCPP__) # include #elif defined(BOOST_HAS_PTHREADS) # define BOOST_LWM_USE_PTHREADS From d84fa738ef4dabe569da8eace30fa409cf32519b Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 22 Jun 2002 15:55:01 +0000 Subject: [PATCH 101/133] Sleep(0) changed to Sleep(1) to (hopefully) avoid livelocks. [SVN r14226] --- include/boost/detail/lwm_win32.hpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/boost/detail/lwm_win32.hpp b/include/boost/detail/lwm_win32.hpp index a54aefc..0bc73bd 100644 --- a/include/boost/detail/lwm_win32.hpp +++ b/include/boost/detail/lwm_win32.hpp @@ -57,7 +57,12 @@ public: { while( winapi::InterlockedExchange(&m_.l_, 1) ) { - winapi::Sleep(0); + // Note: changed to Sleep(1) from Sleep(0). + // According to MSDN, Sleep(0) will never yield + // to a lower-priority thread, whereas Sleep(1) + // will. Performance seems not to be affected. + + winapi::Sleep(1); } } @@ -65,8 +70,8 @@ public: { winapi::InterlockedExchange(&m_.l_, 0); - // Note: adding a Sleep(0) here will make - // the mutex more fair and will increase the overall + // Note: adding a yield here will make + // the spinlock more fair and will increase the overall // performance of some applications substantially in // high contention situations, but will penalize the // low contention / single thread case up to 5x From dca9628be35fa44b03ca833a344b806a5b3d384c Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 9 Jul 2002 12:06:46 +0000 Subject: [PATCH 102/133] Disabled some Borland warnings (David B. Held) [SVN r14368] --- include/boost/detail/lwm_win32.hpp | 8 ++++++++ include/boost/detail/shared_count.hpp | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/boost/detail/lwm_win32.hpp b/include/boost/detail/lwm_win32.hpp index 0bc73bd..abd1869 100644 --- a/include/boost/detail/lwm_win32.hpp +++ b/include/boost/detail/lwm_win32.hpp @@ -18,6 +18,10 @@ #include +#ifdef __BORLANDC__ +# pragma warn -8027 // Functions containing while are not expanded inline +#endif + namespace boost { @@ -83,4 +87,8 @@ public: } // namespace boost +#ifdef __BORLANDC__ +# pragma warn .8027 // Functions containing while are not expanded inline +#endif + #endif // #ifndef BOOST_DETAIL_LWM_WIN32_HPP_INCLUDED diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index cc325ea..673a632 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -28,6 +28,11 @@ #include // for std::less #include // for std::exception +#ifdef __BORLANDC__ +# pragma warn -8026 // Functions with excep. spec. are not expanded inline +# pragma warn -8027 // Functions containing try are not expanded inline +#endif + namespace boost { @@ -389,4 +394,9 @@ inline shared_count::shared_count(weak_count const & r): pi_(r.pi_) } // namespace boost +#ifdef __BORLANDC__ +# pragma warn .8027 // Functions containing try are not expanded inline +# pragma warn .8026 // Functions with excep. spec. are not expanded inline +#endif + #endif // #ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED From af6fe18c9d2f383e10f584df899963aeb89ca1fa Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 15 Jul 2002 12:52:29 +0000 Subject: [PATCH 103/133] Minor fixes. [SVN r14464] --- weak_ptr.htm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/weak_ptr.htm b/weak_ptr.htm index 72104fb..8e284d1 100644 --- a/weak_ptr.htm +++ b/weak_ptr.htm @@ -8,9 +8,9 @@

    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.

    + managed by a shared_ptr. When the 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 @@ -30,7 +30,7 @@ weak_ptr<int> q(p); if(int * r = q.get()) { - // use *r + // use *r }

    Imagine that after the if, but immediately before r @@ -46,7 +46,7 @@ weak_ptr<int> q(p); if(shared_ptr<int> r = make_shared(q)) { - // use *r + // use *r }

    Now r holds a reference to the object that was pointed by q. @@ -101,7 +101,7 @@ if(shared_ptr<int> r = make_shared(q))

    Provides the type of the template parameter T.

    constructors

    -
    explicit weak_ptr();
    +
     weak_ptr();

    Effects: Constructs a weak_ptr.

    Postconditions: use count is 0; the stored From 547888d50736801d9b05971eb3d84a4fa3a5de07 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 17 Jul 2002 15:15:39 +0000 Subject: [PATCH 104/133] Consistent 'bool' conversions; scoped_ptr(auto_ptr); get_pointer(scoped_ptr) added. [SVN r14496] --- include/boost/scoped_array.hpp | 16 +++++++++++++++ include/boost/scoped_ptr.hpp | 37 +++++++++++++++++++++++++++++++++- include/boost/shared_array.hpp | 14 +++++++++++++ include/boost/shared_ptr.hpp | 28 ++++++++++++------------- 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/include/boost/scoped_array.hpp b/include/boost/scoped_array.hpp index 070925c..a62ba2b 100644 --- a/include/boost/scoped_array.hpp +++ b/include/boost/scoped_array.hpp @@ -33,6 +33,8 @@ private: scoped_array(scoped_array const &); scoped_array & operator=(scoped_array const &); + typedef scoped_array this_type; + public: typedef T element_type; @@ -67,6 +69,20 @@ public: return ptr; } + // implicit conversion to "bool" + + typedef T * (this_type::*unspecified_bool_type)() const; + + operator unspecified_bool_type() const // never throws + { + return px == 0? 0: &this_type::get; + } + + bool operator! () const // never throws + { + return px == 0; + } + void swap(scoped_array & b) // never throws { T * tmp = b.ptr; diff --git a/include/boost/scoped_ptr.hpp b/include/boost/scoped_ptr.hpp index f452f7a..73737e9 100644 --- a/include/boost/scoped_ptr.hpp +++ b/include/boost/scoped_ptr.hpp @@ -15,6 +15,10 @@ #include #include +#ifndef BOOST_NO_AUTO_PTR +# include // for std::auto_ptr +#endif + namespace boost { @@ -27,11 +31,13 @@ template class scoped_ptr // noncopyable { private: - T* ptr; + T * ptr; scoped_ptr(scoped_ptr const &); scoped_ptr & operator=(scoped_ptr const &); + typedef scoped_ptr this_type; + public: typedef T element_type; @@ -40,6 +46,14 @@ public: { } +#ifndef BOOST_NO_AUTO_PTR + + explicit scoped_ptr(std::auto_ptr p): ptr(p.release()) // never throws + { + } + +#endif + ~scoped_ptr() // never throws { checked_delete(ptr); @@ -71,6 +85,20 @@ public: return ptr; } + // implicit conversion to "bool" + + typedef T * (this_type::*unspecified_bool_type)() const; + + operator unspecified_bool_type() const // never throws + { + return px == 0? 0: &this_type::get; + } + + bool operator! () const // never throws + { + return px == 0; + } + void swap(scoped_ptr & b) // never throws { T * tmp = b.ptr; @@ -84,6 +112,13 @@ template inline void swap(scoped_ptr & a, scoped_ptr & b) // n a.swap(b); } +// get_pointer(p) is a generic way to say p.get() + +template inline T * get_pointer(scoped_ptr const & p) +{ + return p.get(); +} + } // namespace boost #endif // #ifndef BOOST_SCOPED_PTR_HPP_INCLUDED diff --git a/include/boost/shared_array.hpp b/include/boost/shared_array.hpp index a820abc..880992b 100644 --- a/include/boost/shared_array.hpp +++ b/include/boost/shared_array.hpp @@ -92,6 +92,20 @@ public: return px; } + // implicit conversion to "bool" + + typedef T * (this_type::*unspecified_bool_type)() const; + + operator unspecified_bool_type() const // never throws + { + return px == 0? 0: &this_type::get; + } + + bool operator! () const // never throws + { + return px == 0; + } + bool unique() const // never throws { return pn.unique(); diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index 39df95f..28a6286 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -206,6 +206,20 @@ public: return px; } + // implicit conversion to "bool" + + typedef T * (this_type::*unspecified_bool_type)() const; + + operator unspecified_bool_type() const // never throws + { + return px == 0? 0: &this_type::get; + } + + bool operator! () const // never throws + { + return px == 0; + } + bool unique() const // never throws { return pn.unique(); @@ -216,20 +230,6 @@ public: return pn.use_count(); } - // implicit conversion to "bool" - - typedef long (this_type::*bool_type)() const; - - operator bool_type() const // never throws - { - return px == 0? 0: &this_type::use_count; - } - - bool operator! () const // never throws - { - return px == 0; - } - void swap(shared_ptr & other) // never throws { std::swap(px, other.px); From 33077bda7134644ab9df04812c00d491a540746b Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 19 Jul 2002 20:06:35 +0000 Subject: [PATCH 105/133] Win64 patch (Tim Fenders) [SVN r14537] --- include/boost/detail/winapi.hpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/boost/detail/winapi.hpp b/include/boost/detail/winapi.hpp index 0e9bb72..340036a 100644 --- a/include/boost/detail/winapi.hpp +++ b/include/boost/detail/winapi.hpp @@ -55,10 +55,41 @@ struct critical_section ulong_ptr_type SpinCount; }; +#if defined(_WIN64) + +// Intel 6.0 on Win64 version, posted by Tim Fenders to [boost-users] + +extern "C" long_type __cdecl _InterlockedIncrement(long_type volatile *); +extern "C" long_type __cdecl _InterlockedDecrement(long_type volatile *); +extern "C" long_type __cdecl _InterlockedExchange(long_type volatile *, long_type); + +#pragma intrinsic(_InterlockedIncrement) +#pragma intrinsic(_InterlockedDecrement) +#pragma intrinsic(_InterlockedExchange) + +inline long_type InterlockedIncrement(long_type volatile * lp) +{ + return _InterlockedIncrement(lp); +} + +inline long_type InterlockedDecrement(long_type volatile* lp) +{ + return _InterlockedDecrement(lp); +} + +inline long_type InterlockedExchange(long_type volatile* lp, long_type l) +{ + return _InterlockedExchange(lp, l); +} + +#else + extern "C" __declspec(dllimport) long_type __stdcall InterlockedIncrement(long_type volatile *); extern "C" __declspec(dllimport) long_type __stdcall InterlockedDecrement(long_type volatile *); extern "C" __declspec(dllimport) long_type __stdcall InterlockedExchange(long_type volatile *, long_type); +#endif + extern "C" __declspec(dllimport) void __stdcall Sleep(dword_type); extern "C" __declspec(dllimport) void __stdcall InitializeCriticalSection(critical_section *); From 3f0ebd4c71f99cd373657afb330842845cc3d7a9 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 22 Jul 2002 16:36:52 +0000 Subject: [PATCH 106/133] 'shared_from_this' added. [SVN r14561] --- include/boost/shared_ptr.hpp | 22 ++++++++++++++++++++++ shared_ptr_test.cpp | 27 ++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index 28a6286..bea9e11 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -313,6 +313,28 @@ template inline T * get_pointer(shared_ptr const & p) return p.get(); } +// shared_from_this() creates a shared_ptr from a raw pointer (usually 'this') + +namespace detail +{ + +inline void sp_assert_counted_base(boost::counted_base const *) +{ +} + +template inline T * sp_remove_const(T const * p) +{ + return const_cast(p); +} + +} // namespace detail + +template shared_ptr shared_from_this(T * p) +{ + detail::sp_assert_counted_base(p); + return shared_ptr(detail::sp_remove_const(p)); +} + } // namespace boost #ifdef BOOST_MSVC diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp index f96dfc6..6113d26 100644 --- a/shared_ptr_test.cpp +++ b/shared_ptr_test.cpp @@ -112,6 +112,16 @@ public: std::cout << "Z(" << this << ")::~Z()\n"; } + boost::shared_ptr shared_this() + { + return boost::shared_from_this(this); + } + + boost::shared_ptr shared_this() const + { + return boost::shared_from_this(this); + } + private: Z(Z const &); @@ -331,9 +341,24 @@ int test_main(int, char * []) { // test intrusive counting - boost::shared_ptr pv(new Z); + + boost::shared_ptr pv(new Z); boost::shared_ptr pz = boost::shared_static_cast(pv); BOOST_TEST(pz.use_count() == pz->use_count()); + + // test shared_from_this + + boost::shared_ptr pz2 = pz->shared_this(); + + Z const & z = *pz2; + + boost::shared_ptr pz3 = z.shared_this(); + + BOOST_TEST(pz.use_count() == pz->use_count()); + BOOST_TEST(pz2.use_count() == pz2->use_count()); + BOOST_TEST(pz3.use_count() == pz3->use_count()); + BOOST_TEST(pz.use_count() == pz2.use_count()); + BOOST_TEST(pz.use_count() == pz3.use_count()); } } From f586d3f83ed0a6824f8518f4a0a3679a2066f200 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 23 Jul 2002 12:33:11 +0000 Subject: [PATCH 107/133] shared_ptr support added. [SVN r14570] --- include/boost/shared_ptr.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index bea9e11..ffb8208 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -56,6 +56,15 @@ template<> struct shared_ptr_traits typedef void reference; }; +#if !defined(BOOST_NO_CV_VOID_SPECIALIZATIONS) + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +#endif + } // namespace detail From 018c401e47812ac5b57d2386c001df7dcf4e8fe0 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 23 Jul 2002 15:19:22 +0000 Subject: [PATCH 108/133] Best practices section, thread safety section, design notes added. [SVN r14572] --- shared_ptr.htm | 181 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 170 insertions(+), 11 deletions(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index be047d7..6b5aa1c 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -8,11 +8,13 @@

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

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

    Introduction

    @@ -44,6 +46,43 @@ to shared_ptr<T const>, to shared_ptr<U> where U is an accessible base of T, and to shared_ptr<void>.

    +

    Best Practices

    +

    A simple guideline that nearly eliminates the possibility of memory leaks + is: always use a named smart pointer variable to hold the result of new. + Every occurence of the new keyword in the code should have the + form:

    +
    shared_ptr<T> p(new Y);
    +

    It is, of course, acceptable to use another smart pointer in place of shared_ptr + above; having T and Y be the same type, or + passing arguments to Y's constructor is also OK.

    +

    If you observe this guideline, it naturally follows that you will have no + explicit deletes; try/catch constructs will + be rare.

    +

    Avoid using unnamed shared_ptr temporaries to save typing; to + see why this is dangerous, consider this example:

    +
    +void f(shared_ptr<int>, int);
    +int g();
    +
    +void ok()
    +{
    +    shared_ptr<int> p(new int(2));
    +    f(p, g());
    +}
    +
    +void bad()
    +{
    +    f(shared_ptr<int>(new int(2)), g());
    +}
    +
    +

    The function ok follows the guideline to the letter, whereas + bad constructs the temporary shared_ptr in place, + admitting the possibility of a memory leak. Since function arguments are + evaluated in unspecified order, it is possible for new int(2) to + be evaluated first, g() second, and we may never get to the + shared_ptr constructor if g throws an exception. + See Herb Sutter's treatment of + the issue for more information.

    Synopsis

    namespace boost {
     
    @@ -122,6 +161,22 @@
     			

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

    +

    [The poscondition of use_count() == 1 is too strong. Having the nothrow + guarantee is important, since reset() is specified in terms of + the default constructor, but the current specification requires that a count be + allocated. Therefore, this postcondition will be dropped in a future release. + The use count of a default-constructed shared_ptr, including + all copies created from it, will probably be left unspecified.

    +

    There are two possible nothrow implementations, one stores 0 as a pointer to the + reference count, the other uses a single statically allocated count for all + default-constructed shared_ptrs. The second option is + difficult to achieve in the current header-only reference implementation due to + thread safety issues and initialization order, but it should not be precluded + by the specification.

    +

    A future release may enable shared_ptr construction from a + literal zero, for consistency with built-in pointers. It is not clear yet + whether this constructor should be left implicit, enabling 0 to + be used as a shorthand for shared_ptr<T>().]

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

    Requirements: p must be convertible to T *. Y @@ -138,6 +193,10 @@ use count is 1 holds even if p is 0; invoking delete on a pointer that has a value of 0 is harmless.

    +

    [This constructor has been changed to a template in order to remember the actual + pointer type passed. The destructor will call delete with the + same pointer, complete with its original type, even when T does + not have a virtual destructor, or is void.]

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

    Requirements: p must be convertible to T *. The copy @@ -152,6 +211,14 @@

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

    +

    [Custom deallocators allow a factory function returning a shared_ptr + to insulate the user from its memory allocation strategy. Since the deallocator + is not part of the type, changing the allocation strategy does not break source + or binary compatibility, and does not require a client recompilation. For + example, a "no-op" deallocator is useful when returning a shared_ptr + to a statically allocated object.

    +

    The support for custom deallocators does not impose significant overhead. Other + shared_ptr features still require a deallocator to be kept.]

    shared_ptr(shared_ptr const & r); // never throws
     template<typename Y> shared_ptr(shared_ptr<Y> const & r); // never throws
    @@ -161,6 +228,8 @@ template<typename Y> shared_ptr(shared_ptr<Y> const & r); // nev increased by one.

    Throws: nothing.

    +

    [The postcondition will be relaxed when a default-constructed shared_ptr + is being copied.]

    explicit shared_ptr(weak_ptr const & r);

    Effects: Constructs a shared_ptr, as if by storing a copy of the @@ -171,6 +240,17 @@ template<typename Y> shared_ptr(shared_ptr<Y> const & r); // nev

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

    +

    [This constructor is an optional part of the specification; it depends on the + existence of weak_ptr. It is true that weak_ptr + support imposes overhead on every shared_ptr user, regardless + of whether weak pointers are used.

    +

    On the other hand, cyclic references are a serious problem with all reference + counted designs. Not providing a solution within the library is unacceptable; + if users are forced to reinvent the weak pointer wheel, there is substantial + probability that they will get it wrong, as designing a safe weak_ptr + interface is non-trivial.

    +

    My opinion is that the added functionality is worth the cost. weak_ptr + is provided in the reference implementation as a proof of concept.]

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

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

    @@ -180,6 +260,9 @@ template<typename Y> shared_ptr(shared_ptr<Y> const & r); // nev

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

    +

    [This constructor takes a the source auto_ptr by reference and + not by value, and cannot accept auto_ptr temporaries. This is + by design, as the constructor offers the strong guarantee.]

    destructor

    ~shared_ptr(); // never throws
    @@ -211,6 +294,8 @@ q = p;

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

    +

    [reset() will offer the nothrow guarantee in a future + implementation.]

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

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

    @@ -243,8 +328,12 @@ q = p;

    Returns: use_count() == 1.

    Throws: nothing.

    -

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

    +

    Notes: unique() may be faster than use_count(). + If you are using unique() to implement copy on write, do not rely + on a specific value when the stored pointer is zero.

    +

    [In a future release, unique() will return an unspecified value + for a default-constructed shared_ptr.]

    use_count

    long use_count() const; // never throws
    @@ -255,16 +344,19 @@ q = p; for debugging and testing purposes, not for production code.

    conversions

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

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

    +

    Returns: an unspecified 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 + The actual target type is typically a pointer to a member function, avoiding many of the implicit conversion pitfalls.

    +

    [The conversion to bool is not merely syntactic sugar. It allows shared_ptrs + to be declared in conditions when using shared_dynamic_cast or + make_shared.]

    swap

    void swap(shared_ptr & b); // never throws
    @@ -288,13 +380,19 @@ q = p;
    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] +

    Returns: an unspecified 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.

    +

    [Operator< has been preferred over a std::less + specialization for consistency and legality reasons, as std::less + is required to return the results of operator<, and many + standard algorithms use operator< instead of std::less + for comparisons when a predicate is not supplied.

    +

    The rest of the comparison operators are omitted by design.]

    swap

    template<typename T>
       void swap(shared_ptr<T> & a, shared_ptr<T> & b) // never throws
    @@ -304,6 +402,9 @@ q = p;

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

    +

    [swap is defined in the same namespace as shared_ptr + as this is currently the only legal way to supply a swap function + that has a chance to be used by the standard library.]

    shared_static_cast

    template<typename T, typename U>
       shared_ptr<T> shared_static_cast(shared_ptr<U> const & r); // never throws
    @@ -389,6 +490,65 @@ q = p; 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.

    +

    Thread Safety

    +

    shared_ptr objects offer the same level of thread safety as + built-in types. A shared_ptr instance can be "read" + (accessed using only const operations) simultaneously by multiple threads. + Different shared_ptr instances can be "written to" (accessed + using mutable operations such as operator= or reset) + simultaneosly by multiple threads (even when these instances are copies, and + share the same reference count underneath.)

    +

    Any other simultaneous accesses result in undefined behavior.

    +

    Examples:

    +
    +shared_ptr<int> p(new int(42));
    +
    +//--- Example 1 ---
    +
    +// thread A
    +shared_ptr<int> p2(p); // reads p
    +
    +// thread B
    +shared_ptr<int> p3(p); // OK, multiple reads are safe
    +
    +//--- Example 2 ---
    +
    +// thread A
    +
    +p.reset(new int(1912)); // writes p
    +
    +// thread B
    +p2.reset(); // OK, writes p2
    +
    +//--- Example 3 ---
    +
    +// thread A
    +p = p3; // reads p3, writes p
    +
    +// thread B
    +p3.reset(); // writes p3; undefined, simultaneous read/write
    +
    +//--- Example 4 ---
    +
    +// thread A
    +p3 = p2; // reads p2, writes p3
    +
    +// thread B
    +// p2 goes out of scope: undefined, the destructor is considered a "write access"
    +
    +//--- Example 5 ---
    +
    +// thread A
    +p3.reset(new int(1));
    +
    +// thread B
    +p3.reset(new int(2)); // undefined, multiple writes
    +
    +

    shared_ptr uses Boost.Config + to detect whether the implementation supports threads. If your program is + single-threaded, but your platform is autodetected by Boost.Config + as supporting multiple threads, #define BOOST_DISABLE_THREADS to + eliminate the thread safety overhead.

    Frequently Asked Questions

    Q. There are several variations of shared pointers, with different tradeoffs; why does the smart pointer library supply only a single @@ -408,8 +568,8 @@ q = p; 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?
    +

    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?
    @@ -445,8 +605,7 @@ int * p = a.release(); implementation or a linked list implementation, or some other specific implementation. This is not the intent.


    -

    Revised  - 04 May 2002

    +

    Revised 23 July 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 From 77ad156c52622c7e45e93923b29433d673a59b6e Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 23 Jul 2002 19:12:40 +0000 Subject: [PATCH 109/133] Design notes updated. [SVN r14575] --- shared_ptr.htm | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index 6b5aa1c..d08ff7f 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -196,7 +196,29 @@ void bad()

    [This constructor has been changed to a template in order to remember the actual pointer type passed. The destructor will call delete with the same pointer, complete with its original type, even when T does - not have a virtual destructor, or is void.]

    + not have a virtual destructor, or is void.

    +

    In the current implementation, if p is convertible to counted_base + *, shared_ptr will use the embedded reference + count supplied by counted_base. This is an (experimental) + attempt to provide a way for shared_ptr to be constructed from + a raw pointer such as this. A free function shared_from_this(q) + performs the conversion when q is convertible to counted_base + const *.

    +

    The optional intrusive counting employed by the current implementation allows + shared_ptr to interoperate with intrusive_ptr, an + experimental generic intrusive-counted smart pointer.

    +

    Another possible implementation is to use a global pointer-to-count map instead + of intrusive counting. shared_from_this would no longer be + O(1), which is a concern for some users, although I do not expect any + performance problems, since the operation is rare. Maintaining a global + map is difficult; it needs to be initialized before any shared_ptr + instances are constructed, and the initialization needs to be thread safe. + In addition, under the Windows dynamic library model, it is possible for + several maps to exist.

    +

    It is not yet clear which implementation should be used, or whether the + specification should allow both; nevertheless, the ability to make a shared_ptr + from this is considered essential by experienced smart + pointer users.]

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

    Requirements: p must be convertible to T *. The copy @@ -605,7 +627,8 @@ int * p = a.release(); implementation or a linked list implementation, or some other specific implementation. This is not the intent.


    -

    Revised 23 July 2002

    +

    Revised + 23 July 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 From b5e5c356963190a7dfba56074a82d7e8b38c26f1 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 24 Jul 2002 10:20:30 +0000 Subject: [PATCH 110/133] Minor updates. [SVN r14580] --- shared_ptr.htm | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index d08ff7f..dc0c2cb 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -121,7 +121,7 @@ void bad() bool unique() const; // never throws long use_count() const; // never throws - operator implementation-defined-type () const; // never throws + operator unspecified-bool-type () const; // never throws void swap(shared_ptr<T> & b); // never throws }; @@ -145,6 +145,11 @@ void bad() shared_ptr<T> shared_polymorphic_downcast(shared_ptr<U> const & r); // never throws } +

    [It might be convenient to relax the requirements on shared_ptr's + signature, allowing an additional, defaulted, template parameter. This would + help in detecting possible ODR violations. On the other hand, using shared_ptr + as an argument to a template template parameter requires an exact + signature match.]

    Members

    element_type

    typedef T element_type;
    @@ -413,7 +418,9 @@ q = p; specialization for consistency and legality reasons, as std::less is required to return the results of operator<, and many standard algorithms use operator< instead of std::less - for comparisons when a predicate is not supplied.

    + for comparisons when a predicate is not supplied. Composite objects, like std::pair, + also implement their operator< in terms of their contained + subobjects' operator<.

    The rest of the comparison operators are omitted by design.]

    swap

    template<typename T>
    
    From 053aa108e3268703306a54e56cd8ced5de140925 Mon Sep 17 00:00:00 2001
    From: Peter Dimov 
    Date: Wed, 24 Jul 2002 14:14:17 +0000
    Subject: [PATCH 111/133] Tabs. Grrr.
    
    [SVN r14588]
    ---
     shared_ptr_test.cpp | 36 ++++++++++++++++++------------------
     1 file changed, 18 insertions(+), 18 deletions(-)
    
    diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp
    index 6113d26..07a2528 100644
    --- a/shared_ptr_test.cpp
    +++ b/shared_ptr_test.cpp
    @@ -112,15 +112,15 @@ public:
             std::cout << "Z(" << this << ")::~Z()\n";
         }
     
    -	boost::shared_ptr shared_this()
    -	{
    -		return boost::shared_from_this(this);
    -	}
    +    boost::shared_ptr shared_this()
    +    {
    +        return boost::shared_from_this(this);
    +    }
     
    -	boost::shared_ptr shared_this() const
    -	{
    -		return boost::shared_from_this(this);
    -	}
    +    boost::shared_ptr shared_this() const
    +    {
    +        return boost::shared_from_this(this);
    +    }
     
     private:
     
    @@ -342,23 +342,23 @@ int test_main(int, char * [])
             {
                 // test intrusive counting
     
    -			boost::shared_ptr pv(new Z);
    +            boost::shared_ptr pv(new Z);
                 boost::shared_ptr pz = boost::shared_static_cast(pv);
                 BOOST_TEST(pz.use_count() == pz->use_count());
     
    -			// test shared_from_this
    +            // test shared_from_this
     
    -			boost::shared_ptr pz2 = pz->shared_this();
    +            boost::shared_ptr pz2 = pz->shared_this();
     
    -			Z const & z = *pz2;
    +            Z const & z = *pz2;
     
    -			boost::shared_ptr pz3 = z.shared_this();
    +            boost::shared_ptr pz3 = z.shared_this();
     
    -			BOOST_TEST(pz.use_count() == pz->use_count());
    -			BOOST_TEST(pz2.use_count() == pz2->use_count());
    -			BOOST_TEST(pz3.use_count() == pz3->use_count());
    -			BOOST_TEST(pz.use_count() == pz2.use_count());
    -			BOOST_TEST(pz.use_count() == pz3.use_count());
    +            BOOST_TEST(pz.use_count() == pz->use_count());
    +            BOOST_TEST(pz2.use_count() == pz2->use_count());
    +            BOOST_TEST(pz3.use_count() == pz3->use_count());
    +            BOOST_TEST(pz.use_count() == pz2.use_count());
    +            BOOST_TEST(pz.use_count() == pz3.use_count());
             }
         }
     
    
    From 927fe730936a6d854ad747dc3756342be6887111 Mon Sep 17 00:00:00 2001
    From: Peter Dimov 
    Date: Wed, 24 Jul 2002 15:36:25 +0000
    Subject: [PATCH 112/133] Changed #ifdefs so that member templates aren't
     disabled by an empty config.hpp.
    
    [SVN r14589]
    ---
     include/boost/intrusive_ptr.hpp | 4 ++--
     include/boost/shared_array.hpp  | 4 ++--
     include/boost/shared_ptr.hpp    | 4 ++--
     3 files changed, 6 insertions(+), 6 deletions(-)
    
    diff --git a/include/boost/intrusive_ptr.hpp b/include/boost/intrusive_ptr.hpp
    index 780fe78..4ada734 100644
    --- a/include/boost/intrusive_ptr.hpp
    +++ b/include/boost/intrusive_ptr.hpp
    @@ -61,7 +61,7 @@ public:
             if(p_ != 0) intrusive_ptr_release(p_);
         }
     
    -#ifdef BOOST_MSVC6_MEMBER_TEMPLATES
    +#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES)
     
         template intrusive_ptr(intrusive_ptr const & rhs): p_(rhs.get())
         {
    @@ -75,7 +75,7 @@ public:
             if(p_ != 0) intrusive_ptr_add_ref(p_);
         }
     
    -#ifdef BOOST_MSVC6_MEMBER_TEMPLATES
    +#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES)
     
         template intrusive_ptr & operator=(intrusive_ptr const & rhs)
         {
    diff --git a/include/boost/shared_array.hpp b/include/boost/shared_array.hpp
    index 880992b..c60a85a 100644
    --- a/include/boost/shared_array.hpp
    +++ b/include/boost/shared_array.hpp
    @@ -17,7 +17,7 @@
     
     #include    // for broken compiler workarounds
     
    -#ifndef BOOST_MSVC6_MEMBER_TEMPLATES
    +#if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES)
     #include 
     #else
     
    @@ -151,6 +151,6 @@ template void swap(shared_array & a, shared_array & b) // neve
     
     } // namespace boost
     
    -#endif  // #ifndef BOOST_MSVC6_MEMBER_TEMPLATES
    +#endif  // #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES)
     
     #endif  // #ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED
    diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp
    index ffb8208..2634929 100644
    --- a/include/boost/shared_ptr.hpp
    +++ b/include/boost/shared_ptr.hpp
    @@ -17,7 +17,7 @@
     
     #include    // for broken compiler workarounds
     
    -#ifndef BOOST_MSVC6_MEMBER_TEMPLATES
    +#if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES)
     #include 
     #else
     
    @@ -350,6 +350,6 @@ template shared_ptr shared_from_this(T * p)
     # pragma warning(pop)
     #endif    
     
    -#endif  // #ifndef BOOST_MSVC6_MEMBER_TEMPLATES
    +#endif  // #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES)
     
     #endif  // #ifndef BOOST_SHARED_PTR_HPP_INCLUDED
    
    From 5328674c2dd6a8a3ca1f123f398eeb2eb0c8343d Mon Sep 17 00:00:00 2001
    From: Peter Dimov 
    Date: Fri, 26 Jul 2002 14:18:21 +0000
    Subject: [PATCH 113/133] Minor scoped_* fix (px -> ptr) (Thanks to Bertolt
     Mildner)
    
    [SVN r14619]
    ---
     include/boost/scoped_array.hpp | 4 ++--
     include/boost/scoped_ptr.hpp   | 4 ++--
     2 files changed, 4 insertions(+), 4 deletions(-)
    
    diff --git a/include/boost/scoped_array.hpp b/include/boost/scoped_array.hpp
    index a62ba2b..8c7fdcc 100644
    --- a/include/boost/scoped_array.hpp
    +++ b/include/boost/scoped_array.hpp
    @@ -75,12 +75,12 @@ public:
     
         operator unspecified_bool_type() const // never throws
         {
    -        return px == 0? 0: &this_type::get;
    +        return ptr == 0? 0: &this_type::get;
         }
     
         bool operator! () const // never throws
         {
    -        return px == 0;
    +        return ptr == 0;
         }
     
         void swap(scoped_array & b) // never throws
    diff --git a/include/boost/scoped_ptr.hpp b/include/boost/scoped_ptr.hpp
    index 73737e9..738ad1b 100644
    --- a/include/boost/scoped_ptr.hpp
    +++ b/include/boost/scoped_ptr.hpp
    @@ -91,12 +91,12 @@ public:
     
         operator unspecified_bool_type() const // never throws
         {
    -        return px == 0? 0: &this_type::get;
    +        return ptr == 0? 0: &this_type::get;
         }
     
         bool operator! () const // never throws
         {
    -        return px == 0;
    +        return ptr == 0;
         }
     
         void swap(scoped_ptr & b) // never throws
    
    From 89435a6287ac8d157dc08ef38b33865073e1b355 Mon Sep 17 00:00:00 2001
    From: Peter Dimov 
    Date: Sat, 27 Jul 2002 16:02:26 +0000
    Subject: [PATCH 114/133] get_pointer added.
    
    [SVN r14628]
    ---
     shared_ptr.htm | 15 +++++++++++++--
     1 file changed, 13 insertions(+), 2 deletions(-)
    
    diff --git a/shared_ptr.htm b/shared_ptr.htm
    index dc0c2cb..1333f73 100644
    --- a/shared_ptr.htm
    +++ b/shared_ptr.htm
    @@ -135,6 +135,8 @@ void bad()
     
       template<typename T> void swap(shared_ptr<T> & a, shared_ptr<T> & b); // never throws
     
    +  template<typename T> T * get_pointer(shared_ptr<T> const & p); // 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>
    @@ -424,7 +426,7 @@ q = p;
     		

    The rest of the comparison operators are omitted by design.]

    swap

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

    Effects: Equivalent to a.swap(b).

    Throws: nothing.

    @@ -434,6 +436,15 @@ q = p;

    [swap is defined in the same namespace as shared_ptr as this is currently the only legal way to supply a swap function that has a chance to be used by the standard library.]

    +

    get_pointer

    +
    template<typename T>
    +  T * get_pointer(shared_ptr<T> const & p); // never throws
    +
    +

    Returns: p.get().

    +

    Throws: nothing.

    +

    Notes: Provided as an aid to generic programming. Used by + mem_fn.

    +

    shared_static_cast

    template<typename T, typename U>
       shared_ptr<T> shared_static_cast(shared_ptr<U> const & r); // never throws
    @@ -634,7 +645,7 @@ int * p = a.release(); implementation or a linked list implementation, or some other specific implementation. This is not the intent.


    -

    Revised +

    Revised 23 July 2002

    Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. Copyright 2002 Peter Dimov. Permission to copy, use, modify, sell and From c06b4206f267cf27b067906bb68ee5d8b2b9fb40 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 13 Aug 2002 15:58:12 +0000 Subject: [PATCH 115/133] #include added. [SVN r14813] --- shared_ptr_test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp index 07a2528..262a9b5 100644 --- a/shared_ptr_test.cpp +++ b/shared_ptr_test.cpp @@ -22,6 +22,8 @@ #include #include +#include + bool boost_error(char const *, char const *, char const *, long) { return true; From e650c7ff1607c033cb38850d9cad350fabc9f90e Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 14 Aug 2002 11:59:13 +0000 Subject: [PATCH 116/133] Changed BOOST_TEST(p) to BOOST_TEST(p? true: false) to make sure the right thing is being tested. [SVN r14834] --- shared_ptr_test.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp index 262a9b5..883d870 100644 --- a/shared_ptr_test.cpp +++ b/shared_ptr_test.cpp @@ -190,7 +190,10 @@ template void test_is_zero(boost::shared_ptr const & p) template void test_is_nonzero(boost::shared_ptr const & p) { - BOOST_TEST(p); + // p? true: false is used to test p in a boolean context. + // BOOST_TEST(p) is not guaranteed to test the conversion, + // as the macro might test !!p instead. + BOOST_TEST(p? true: false); BOOST_TEST(p.get() != 0); } From a09c2e556f9421da9f0e7e74b98c89a5599b17f8 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 14 Aug 2002 12:27:22 +0000 Subject: [PATCH 117/133] BOOST_NO_EXCEPTIONS support added. [SVN r14835] --- include/boost/detail/shared_array_nmt.hpp | 44 +++++++++++++++-------- include/boost/detail/shared_count.hpp | 18 +++++++++- include/boost/detail/shared_ptr_nmt.hpp | 29 +++++++++++---- include/boost/shared_ptr.hpp | 5 +-- 4 files changed, 73 insertions(+), 23 deletions(-) diff --git a/include/boost/detail/shared_array_nmt.hpp b/include/boost/detail/shared_array_nmt.hpp index 3ff1954..8e9b727 100644 --- a/include/boost/detail/shared_array_nmt.hpp +++ b/include/boost/detail/shared_array_nmt.hpp @@ -17,11 +17,13 @@ #include #include +#include #include -#include // for std::ptrdiff_t -#include // for std::swap -#include // for std::less +#include // for std::ptrdiff_t +#include // for std::swap +#include // for std::less +#include // for std::bad_alloc namespace boost { @@ -38,22 +40,36 @@ public: explicit shared_array(T * p = 0): px(p) { +#ifndef BOOST_NO_EXCEPTIONS + try // prevent leak if new throws { pn = new count_type(1); } catch(...) { - checked_array_delete(p); + boost::checked_array_delete(p); throw; - } + } + +#else + + pn = new count_type(1); + + if(pn == 0) + { + boost::checked_array_delete(p); + boost::throw_exception(std::bad_alloc()); + } + +#endif } - + ~shared_array() { if(--*pn == 0) { - checked_array_delete(px); + boost::checked_array_delete(px); delete pn; } } @@ -63,19 +79,19 @@ public: pn = r.pn; ++*pn; } - + shared_array & operator=(shared_array const & r) { shared_array(r).swap(*this); return *this; } - + void reset(T * p = 0) { BOOST_ASSERT(p == 0 || p != px); shared_array(p).swap(*this); } - + T * get() const // never throws { return px; @@ -87,7 +103,7 @@ public: BOOST_ASSERT(i >= 0); return px[i]; } - + long use_count() const // never throws { return *pn; @@ -97,15 +113,15 @@ public: { return *pn == 1; } - + void swap(shared_array & 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 diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 673a632..17aeb9d 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -23,10 +23,12 @@ #endif #include +#include #include #include // for std::less #include // for std::exception +#include // for std::bad_alloc #ifdef __BORLANDC__ # pragma warn -8026 // Functions with excep. spec. are not expanded inline @@ -95,7 +97,7 @@ public: #ifdef BOOST_HAS_THREADS mutex_type::scoped_lock lock(mtx_); #endif - if(use_count_ == 0 && weak_count_ != 0) throw use_count_is_zero(); + if(use_count_ == 0 && weak_count_ != 0) boost::throw_exception(boost::use_count_is_zero()); ++use_count_; ++weak_count_; } @@ -235,6 +237,8 @@ public: template shared_count(P p, D d, void const * = 0): pi_(0) { +#ifndef BOOST_NO_EXCEPTIONS + try { pi_ = new counted_base_impl(p, d, 1, 1); @@ -244,6 +248,18 @@ public: d(p); // delete p throw; } + +#else + + pi_ = new counted_base_impl(p, d, 1, 1); + + if(pi_ == 0) + { + d(p); // delete p + boost::throw_exception(std::bad_alloc()); + } + +#endif } template shared_count(P, D, counted_base * pi): pi_(pi) diff --git a/include/boost/detail/shared_ptr_nmt.hpp b/include/boost/detail/shared_ptr_nmt.hpp index 79d5b5d..14fbe65 100644 --- a/include/boost/detail/shared_ptr_nmt.hpp +++ b/include/boost/detail/shared_ptr_nmt.hpp @@ -17,14 +17,16 @@ #include #include +#include #include #ifndef BOOST_NO_AUTO_PTR -#include // for std::auto_ptr +# include // for std::auto_ptr #endif -#include // for std::swap -#include // for std::less +#include // for std::swap +#include // for std::less +#include // for std::bad_alloc namespace boost { @@ -38,25 +40,40 @@ private: public: typedef T element_type; + typedef T value_type; explicit shared_ptr(T * p = 0): px(p) { +#ifndef BOOST_NO_EXCEPTIONS + try // prevent leak if new throws { pn = new count_type(1); } catch(...) { - checked_delete(p); + boost::checked_delete(p); throw; - } + } + +#else + + pn = new count_type(1); + + if(pn == 0) + { + boost::checked_delete(p); + boost::throw_exception(std::bad_alloc()); + } + +#endif } ~shared_ptr() { if(--*pn == 0) { - checked_delete(px); + boost::checked_delete(px); delete pn; } } diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index 2634929..8f55948 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -23,7 +23,7 @@ #include #include - +#include #include #include // for std::auto_ptr @@ -90,6 +90,7 @@ private: public: typedef T element_type; + typedef T value_type; shared_ptr(): px(0), pn() { @@ -146,7 +147,7 @@ public: { if (px == 0) { - throw std::bad_cast(); + boost::throw_exception(std::bad_cast()); } } From 8436c4d271ea7fa63fe488e0b34c1ada698c73e0 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 16 Aug 2002 15:55:19 +0000 Subject: [PATCH 118/133] #pragma option -pc around use_count_is_zero added for Borland 5.5.1, to enable compilation with -ps set. [SVN r14927] --- include/boost/detail/shared_count.hpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 17aeb9d..299fadb 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -38,16 +38,31 @@ namespace boost { +// The standard library that comes with Borland C++ 5.5.1 +// defines std::exception and its members as having C calling +// convention (-pc). When the definition of use_count_is_zero +// is compiled with -ps, the compiler issues an error. +// Hence, the temporary #pragma option -pc below. The version +// check is deliberately conservative. + +#if defined(__BORLANDC__) && __BORLANDC__ == 0x551 +# pragma option push -pc +#endif + class use_count_is_zero: public std::exception { public: virtual char const * what() const throw() { - return "use_count_is_zero"; + return "boost::use_count_is_zero"; } }; +#if defined(__BORLANDC__) && __BORLANDC__ == 0x551 +# pragma option pop +#endif + class counted_base { private: From c2ee5172b0e94692524b52ca5da3e11678d9f8b9 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 16 Aug 2002 16:41:16 +0000 Subject: [PATCH 119/133] Switched to for testing. [SVN r14932] --- shared_ptr_mt_test.cpp | 5 +- shared_ptr_test.cpp | 7 +- smart_ptr_test.cpp | 355 +++++++++++++++++++++-------------------- 3 files changed, 182 insertions(+), 185 deletions(-) diff --git a/shared_ptr_mt_test.cpp b/shared_ptr_mt_test.cpp index 185bd99..52828f5 100644 --- a/shared_ptr_mt_test.cpp +++ b/shared_ptr_mt_test.cpp @@ -19,9 +19,6 @@ #include #include -#define BOOST_INCLUDE_MAIN -#include - #include #include #include @@ -153,7 +150,7 @@ int const m = 16; // threads char const * implementation = "spinlock"; #endif -int test_main( int, char ** ) +int main() { std::printf("%s: %s, %d threads, %d iterations: ", title, implementation, m, n); diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp index 883d870..56f6e46 100644 --- a/shared_ptr_test.cpp +++ b/shared_ptr_test.cpp @@ -16,8 +16,7 @@ // warranty, and with no claim as to its suitability for any purpose. // -#define BOOST_INCLUDE_MAIN -#include +#include #include #include @@ -197,7 +196,7 @@ template void test_is_nonzero(boost::shared_ptr const & p) BOOST_TEST(p.get() != 0); } -int test_main(int, char * []) +int main() { using namespace boost; @@ -369,5 +368,5 @@ int test_main(int, char * []) BOOST_TEST(cnt == 0); - return 0; + return boost::report_errors(); } diff --git a/smart_ptr_test.cpp b/smart_ptr_test.cpp index 79edf7e..eead369 100644 --- a/smart_ptr_test.cpp +++ b/smart_ptr_test.cpp @@ -18,8 +18,7 @@ #include #include -#define BOOST_INCLUDE_MAIN -#include +#include #include #include @@ -84,212 +83,214 @@ Incomplete * check_incomplete( shared_ptr& incomplete, cout << incomplete.use_count() << ' ' << incomplete.unique() << '\n'; return incomplete.get(); } -// main --------------------------------------------------------------------// // This isn't a very systematic test; it just hits some of the basics. -int test_main( int, char *[] ) { +void test() +{ + BOOST_TEST( UDT_use_count == 0 ); // reality check - BOOST_TEST( UDT_use_count == 0 ); // reality check + // test scoped_ptr with a built-in type + long * lp = new long; + scoped_ptr sp ( lp ); + BOOST_TEST( sp.get() == lp ); + BOOST_TEST( lp == sp.get() ); + BOOST_TEST( &*sp == lp ); - // test scoped_ptr with a built-in type - long * lp = new long; - scoped_ptr 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 = 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 ); - 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_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() ); - // 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 ); - strcpy( sa.get(), "Hot Dog with mustard and relish" ); - BOOST_TEST( strcmp( sa.get(), "Hot Dog with mustard and relish" ) == 0 ); - BOOST_TEST( strcmp( sap, "Hot Dog with mustard and relish" ) == 0 ); + BOOST_TEST( sa[0] == 'H' ); + BOOST_TEST( sa[30] == 'h' ); - BOOST_TEST( sa[0] == 'H' ); - BOOST_TEST( sa[30] == 'h' ); + sa[0] = 'N'; + sa[4] = 'd'; + BOOST_TEST( strcmp( sap, "Not dog with mustard and relish" ) == 0 ); - sa[0] = 'N'; - sa[4] = 'd'; - BOOST_TEST( strcmp( sap, "Not dog with mustard and relish" ) == 0 ); + sa.reset(); + BOOST_TEST( sa.get() == 0 ); - sa.reset(); - BOOST_TEST( sa.get() == 0 ); + // test shared_ptr with a built-in type + int * ip = new int; + shared_ptr cp ( ip ); + BOOST_TEST( ip == cp.get() ); + BOOST_TEST( cp.use_count() == 1 ); - // test shared_ptr with a built-in type - int * ip = new int; - shared_ptr 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 ); - *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 ); - 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 ); - 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) ) ); + 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 ); - // 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 ); + shared_ptr cp4; + swap( cp2, cp4 ); + BOOST_TEST( cp4.use_count() == 3 ); + BOOST_TEST( *cp4 == 87654 ); + BOOST_TEST( cp2.get() == 0 ); - strcpy( ca.get(), "Hot Dog with mustard and relish" ); - BOOST_TEST( strcmp( ca.get(), "Hot Dog with mustard and relish" ) == 0 ); - BOOST_TEST( strcmp( cap, "Hot Dog with mustard and relish" ) == 0 ); + set< shared_ptr > scp; + scp.insert(cp4); + BOOST_TEST( scp.find(cp4) != scp.end() ); + BOOST_TEST( scp.find(cp4) == scp.find( shared_ptr(cp4) ) ); - BOOST_TEST( ca[0] == 'H' ); - BOOST_TEST( ca[30] == 'h' ); - - shared_array ca2 ( ca ); - shared_array ca3 ( ca2 ); + // 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 ); - ca[0] = 'N'; - ca[4] = 'd'; - BOOST_TEST( strcmp( ca.get(), "Not dog with mustard and relish" ) == 0 ); - BOOST_TEST( strcmp( ca2.get(), "Not dog with mustard and relish" ) == 0 ); - BOOST_TEST( strcmp( ca3.get(), "Not dog with mustard and relish" ) == 0 ); - BOOST_TEST( ca.use_count() == 3 ); - BOOST_TEST( ca2.use_count() == 3 ); - BOOST_TEST( ca3.use_count() == 3 ); - ca2.reset(); - BOOST_TEST( ca.use_count() == 2 ); - BOOST_TEST( ca3.use_count() == 2 ); - BOOST_TEST( ca2.use_count() == 1 ); + strcpy( ca.get(), "Hot Dog with mustard and relish" ); + BOOST_TEST( strcmp( ca.get(), "Hot Dog with mustard and relish" ) == 0 ); + BOOST_TEST( strcmp( cap, "Hot Dog with mustard and relish" ) == 0 ); - ca.reset(); - BOOST_TEST( ca.get() == 0 ); + BOOST_TEST( ca[0] == 'H' ); + BOOST_TEST( ca[30] == 'h' ); - shared_array 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) ) ); + shared_array ca2 ( ca ); + shared_array ca3 ( ca2 ); - // test shared_array with user defined type - shared_array udta ( new UDT[3] ); + ca[0] = 'N'; + ca[4] = 'd'; + BOOST_TEST( strcmp( ca.get(), "Not dog with mustard and relish" ) == 0 ); + BOOST_TEST( strcmp( ca2.get(), "Not dog with mustard and relish" ) == 0 ); + BOOST_TEST( strcmp( ca3.get(), "Not dog with mustard and relish" ) == 0 ); + BOOST_TEST( ca.use_count() == 3 ); + BOOST_TEST( ca2.use_count() == 3 ); + BOOST_TEST( ca3.use_count() == 3 ); + ca2.reset(); + BOOST_TEST( ca.use_count() == 2 ); + BOOST_TEST( ca3.use_count() == 2 ); + BOOST_TEST( ca2.use_count() == 1 ); - udta[0].value( 111 ); - udta[1].value( 222 ); - udta[2].value( 333 ); - shared_array udta2 ( udta ); + ca.reset(); + BOOST_TEST( ca.get() == 0 ); - BOOST_TEST( udta[0].value() == 111 ); - BOOST_TEST( udta[1].value() == 222 ); - BOOST_TEST( udta[2].value() == 333 ); - BOOST_TEST( udta2[0].value() == 111 ); - BOOST_TEST( udta2[1].value() == 222 ); - BOOST_TEST( udta2[2].value() == 333 ); - udta2.reset(); - BOOST_TEST( udta2.get() == 0 ); - BOOST_TEST( udta.use_count() == 1 ); - BOOST_TEST( udta2.use_count() == 1 ); + shared_array ca4; + swap( ca3, ca4 ); + BOOST_TEST( ca4.use_count() == 1 ); + BOOST_TEST( strcmp( ca4.get(), "Not dog with mustard and relish" ) == 0 ); + BOOST_TEST( ca3.get() == 0 ); - BOOST_TEST( UDT_use_count == 4 ); // reality check + set< shared_array > sca; + sca.insert(ca4); + BOOST_TEST( sca.find(ca4) != sca.end() ); + BOOST_TEST( sca.find(ca4) == sca.find( shared_array(ca4) ) ); - // 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 ); + // test shared_array with user defined type + shared_array udta ( new UDT[3] ); - sup->value( 54321 ) ; - BOOST_TEST( sup->value() == 54321 ); - BOOST_TEST( up->value() == 54321 ); + udta[0].value( 111 ); + udta[1].value( 222 ); + udta[2].value( 333 ); + shared_array udta2 ( udta ); - 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 ); + BOOST_TEST( udta[0].value() == 111 ); + BOOST_TEST( udta[1].value() == 222 ); + BOOST_TEST( udta[2].value() == 333 ); + BOOST_TEST( udta2[0].value() == 111 ); + BOOST_TEST( udta2[1].value() == 222 ); + BOOST_TEST( udta2[2].value() == 333 ); + udta2.reset(); + BOOST_TEST( udta2.get() == 0 ); + BOOST_TEST( udta.use_count() == 1 ); + BOOST_TEST( udta2.use_count() == 1 ); - cout << "OK\n"; + BOOST_TEST( UDT_use_count == 4 ); // reality check - new char[12345]; // deliberate memory leak to verify leaks detected + // test shared_ptr with a user defined type + UDT * up = new UDT; + shared_ptr sup ( up ); + BOOST_TEST( up == sup.get() ); + BOOST_TEST( sup.use_count() == 1 ); - return 0; - } // main + sup->value( 54321 ) ; + BOOST_TEST( sup->value() == 54321 ); + BOOST_TEST( up->value() == 54321 ); + shared_ptr sup2; + sup2 = sup; + BOOST_TEST( sup2->value() == 54321 ); + BOOST_TEST( sup.use_count() == 2 ); + BOOST_TEST( sup2.use_count() == 2 ); + sup2 = sup2; + BOOST_TEST( sup2->value() == 54321 ); + BOOST_TEST( sup.use_count() == 2 ); + BOOST_TEST( sup2.use_count() == 2 ); + + cout << "OK\n"; + + new char[12345]; // deliberate memory leak to verify leaks detected +} + +int main() +{ + test(); + return boost::report_errors(); +} From 09016db3c3bf9bac9efeb97462334d45e00bc31f Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 17 Aug 2002 13:05:25 +0000 Subject: [PATCH 120/133] Note added to shared_ptr(Y*, D). [SVN r14942] --- shared_ptr.htm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index 1333f73..013d307 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -247,7 +247,10 @@ void bad() example, a "no-op" deallocator is useful when returning a shared_ptr to a statically allocated object.

    The support for custom deallocators does not impose significant overhead. Other - shared_ptr features still require a deallocator to be kept.]

    + shared_ptr features still require a deallocator to be kept.

    +

    The requirement that the copy constructor of D does not throw is too strong. + It will be removed when some core language issues are resolved (cv-qualified + function types, partial ordering clarifications.)]

    shared_ptr(shared_ptr const & r); // never throws
     template<typename Y> shared_ptr(shared_ptr<Y> const & r); // never throws
    From bd4f575567ad87839f5c33bcc2ac37995c10f2fb Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 17 Aug 2002 13:33:41 +0000 Subject: [PATCH 121/133] HPUX 10.20 patch (problem reported by Tom Matelich) [SVN r14943] --- include/boost/detail/lwm_pthreads.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/boost/detail/lwm_pthreads.hpp b/include/boost/detail/lwm_pthreads.hpp index ba8d762..8ee5550 100644 --- a/include/boost/detail/lwm_pthreads.hpp +++ b/include/boost/detail/lwm_pthreads.hpp @@ -37,7 +37,14 @@ public: lightweight_mutex() { + +// HPUX 10.20 / DCE has a nonstandard pthread_mutex_init + +#if defined(__hpux) && defined(_DECTHREADS_) + pthread_mutex_init(&m_, pthread_mutexattr_default); +#else pthread_mutex_init(&m_, 0); +#endif } ~lightweight_mutex() From 92999be43626c9271226777a7408fbe11b9894ce Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 19 Aug 2002 16:23:07 +0000 Subject: [PATCH 122/133] Corrected the shared_ptr(auto_ptr &) postcondition (reported by Maciej Sobczak) [SVN r14953] --- shared_ptr.htm | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index 013d307..72c63f3 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -96,8 +96,8 @@ void bad() typedef T element_type; - shared_ptr (); - template<typename Y> explicit shared_ptr (Y * p); + 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 @@ -248,9 +248,9 @@ void bad() to a statically allocated object.

    The support for custom deallocators does not impose significant overhead. Other shared_ptr features still require a deallocator to be kept.

    -

    The requirement that the copy constructor of D does not throw is too strong. - It will be removed when some core language issues are resolved (cv-qualified - function types, partial ordering clarifications.)]

    +

    The requirement that the copy constructor of D does not throw is too + strong. It will be removed when some core language issues are resolved + (cv-qualified function types, partial ordering clarifications.)]

    shared_ptr(shared_ptr const & r); // never throws
     template<typename Y> shared_ptr(shared_ptr<Y> const & r); // never throws
    @@ -286,8 +286,7 @@ template<typename Y> shared_ptr(shared_ptr<Y> const & r); // nev
    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.

    +

    Postconditions: use count is 1.

    Throws: std::bad_alloc.

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

    From e84eb3f1ba7b162c2c683ca05181f4ad56fe2f47 Mon Sep 17 00:00:00 2001 From: John Maddock Date: Tue, 20 Aug 2002 11:08:11 +0000 Subject: [PATCH 123/133] Added #pragma's to fix codeguard errors. [SVN r14984] --- include/boost/detail/shared_count.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 299fadb..6de061a 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -202,6 +202,13 @@ inline void intrusive_ptr_release(counted_base * p) namespace detail { +// +// Borland's Codeguard trips up over the -Vx- option here: +// +#ifdef __CODEGUARD__ +#pragma option push -Vx- +#endif + template class counted_base_impl: public counted_base { private: @@ -344,6 +351,11 @@ public: } }; +#ifdef __CODEGUARD__ +#pragma option pop +#endif + + class weak_count { private: From b9dceb23401a9917257e5ecc89575c161ee1c0d2 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 26 Aug 2002 15:27:23 +0000 Subject: [PATCH 124/133] *_ptr.hpp: - Added detail::is_pointerlike_helper function templates for Signals weak_ptr.hpp: - Added get_pointer function template for weak_ptr [SVN r15099] --- include/boost/intrusive_ptr.hpp | 6 ++++++ include/boost/scoped_ptr.hpp | 6 ++++++ include/boost/shared_ptr.hpp | 7 +++++++ include/boost/weak_ptr.hpp | 13 +++++++++++++ 4 files changed, 32 insertions(+) diff --git a/include/boost/intrusive_ptr.hpp b/include/boost/intrusive_ptr.hpp index 4ada734..0a62544 100644 --- a/include/boost/intrusive_ptr.hpp +++ b/include/boost/intrusive_ptr.hpp @@ -193,6 +193,12 @@ template T * get_pointer(intrusive_ptr const & p) return p.get(); } +namespace detail { + // is_pointerlike_helper enables Signals library to recognize intrusive_ptr + template + type_traits::yes_type is_pointerlike_helper(const intrusive_ptr&, int); +} // end namespace detail + } // namespace boost #ifdef BOOST_MSVC diff --git a/include/boost/scoped_ptr.hpp b/include/boost/scoped_ptr.hpp index 738ad1b..7adc0e8 100644 --- a/include/boost/scoped_ptr.hpp +++ b/include/boost/scoped_ptr.hpp @@ -119,6 +119,12 @@ template inline T * get_pointer(scoped_ptr const & p) return p.get(); } +namespace detail { + // is_pointerlike_helper enables Signals library to recognize scoped_ptr + template + type_traits::yes_type is_pointerlike_helper(const scoped_ptr&, int); +} // end namespace detail + } // namespace boost #endif // #ifndef BOOST_SCOPED_PTR_HPP_INCLUDED diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index 8f55948..d9cc25d 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include // for std::auto_ptr #include // for std::swap @@ -323,6 +324,12 @@ template inline T * get_pointer(shared_ptr const & p) return p.get(); } +namespace detail { + // is_pointerlike_helper enables Signals library to recognize shared_ptr + template + type_traits::yes_type is_pointerlike_helper(const shared_ptr&, int); +} // end namespace detail + // shared_from_this() creates a shared_ptr from a raw pointer (usually 'this') namespace detail diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index e04b4f1..dc11ca0 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -168,6 +168,19 @@ template shared_ptr make_shared(weak_ptr const & r) // never thro } } +// mem_fn support + +template T * get_pointer(weak_ptr const & p) +{ + return p.get(); +} + +namespace detail { + // is_pointerlike_helper enables Signals library to recognize intrusive_ptr + template + type_traits::yes_type is_pointerlike_helper(const weak_ptr&, int); +} // end namespace detail + } // namespace boost #ifdef BOOST_MSVC From e77889679f7ac34c8f6c45d8b6a94b90e9b15945 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 27 Aug 2002 13:33:22 +0000 Subject: [PATCH 125/133] intrusive_ptr.hpp: scoped_ptr.hpp: - include [SVN r15104] --- include/boost/intrusive_ptr.hpp | 1 + include/boost/scoped_ptr.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/include/boost/intrusive_ptr.hpp b/include/boost/intrusive_ptr.hpp index 0a62544..36bc321 100644 --- a/include/boost/intrusive_ptr.hpp +++ b/include/boost/intrusive_ptr.hpp @@ -20,6 +20,7 @@ #endif #include // std::less +#include namespace boost { diff --git a/include/boost/scoped_ptr.hpp b/include/boost/scoped_ptr.hpp index 7adc0e8..77c77a5 100644 --- a/include/boost/scoped_ptr.hpp +++ b/include/boost/scoped_ptr.hpp @@ -14,6 +14,7 @@ #include #include +#include #ifndef BOOST_NO_AUTO_PTR # include // for std::auto_ptr From c02fee701341a32b49cc12b54f58b7ab25d6c77b Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 29 Aug 2002 13:49:05 +0000 Subject: [PATCH 126/133] *_ptr.hpp: - Revert addition of is_pointerlike_helper weak_ptr.hpp: - Revert addition of get_pointer [SVN r15108] --- include/boost/intrusive_ptr.hpp | 7 ------- include/boost/scoped_ptr.hpp | 7 ------- include/boost/shared_ptr.hpp | 7 ------- include/boost/weak_ptr.hpp | 13 ------------- 4 files changed, 34 deletions(-) diff --git a/include/boost/intrusive_ptr.hpp b/include/boost/intrusive_ptr.hpp index 36bc321..4ada734 100644 --- a/include/boost/intrusive_ptr.hpp +++ b/include/boost/intrusive_ptr.hpp @@ -20,7 +20,6 @@ #endif #include // std::less -#include namespace boost { @@ -194,12 +193,6 @@ template T * get_pointer(intrusive_ptr const & p) return p.get(); } -namespace detail { - // is_pointerlike_helper enables Signals library to recognize intrusive_ptr - template - type_traits::yes_type is_pointerlike_helper(const intrusive_ptr&, int); -} // end namespace detail - } // namespace boost #ifdef BOOST_MSVC diff --git a/include/boost/scoped_ptr.hpp b/include/boost/scoped_ptr.hpp index 77c77a5..738ad1b 100644 --- a/include/boost/scoped_ptr.hpp +++ b/include/boost/scoped_ptr.hpp @@ -14,7 +14,6 @@ #include #include -#include #ifndef BOOST_NO_AUTO_PTR # include // for std::auto_ptr @@ -120,12 +119,6 @@ template inline T * get_pointer(scoped_ptr const & p) return p.get(); } -namespace detail { - // is_pointerlike_helper enables Signals library to recognize scoped_ptr - template - type_traits::yes_type is_pointerlike_helper(const scoped_ptr&, int); -} // end namespace detail - } // namespace boost #endif // #ifndef BOOST_SCOPED_PTR_HPP_INCLUDED diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index d9cc25d..8f55948 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -25,7 +25,6 @@ #include #include #include -#include #include // for std::auto_ptr #include // for std::swap @@ -324,12 +323,6 @@ template inline T * get_pointer(shared_ptr const & p) return p.get(); } -namespace detail { - // is_pointerlike_helper enables Signals library to recognize shared_ptr - template - type_traits::yes_type is_pointerlike_helper(const shared_ptr&, int); -} // end namespace detail - // shared_from_this() creates a shared_ptr from a raw pointer (usually 'this') namespace detail diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index dc11ca0..e04b4f1 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -168,19 +168,6 @@ template shared_ptr make_shared(weak_ptr const & r) // never thro } } -// mem_fn support - -template T * get_pointer(weak_ptr const & p) -{ - return p.get(); -} - -namespace detail { - // is_pointerlike_helper enables Signals library to recognize intrusive_ptr - template - type_traits::yes_type is_pointerlike_helper(const weak_ptr&, int); -} // end namespace detail - } // namespace boost #ifdef BOOST_MSVC From b916445dd8c914114da74daad3a2c1b7cc562824 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 29 Aug 2002 15:18:04 +0000 Subject: [PATCH 127/133] weak_ptr documentation updates; get() declared deprecated. [SVN r15111] --- include/boost/weak_ptr.hpp | 6 +++++- weak_ptr.htm | 31 +++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index e04b4f1..c76cb28 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -76,7 +76,7 @@ public: this_type().swap(*this); } - T * get() const // never throws; unsafe in multithreaded programs! + T * get() const // never throws; deprecated, removal pending, don't use { return pn.use_count() == 0? 0: px; } @@ -168,6 +168,10 @@ template shared_ptr make_shared(weak_ptr const & r) // never thro } } +// Note: there is no get_pointer overload for weak_ptr. +// This is intentional. Even get() will disappear in a +// future release; these accessors are too error-prone. + } // namespace boost #ifdef BOOST_MSVC diff --git a/weak_ptr.htm b/weak_ptr.htm index 8e284d1..92bc284 100644 --- a/weak_ptr.htm +++ b/weak_ptr.htm @@ -7,10 +7,15 @@

    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 last shared_ptr to the object - goes away and the object is deleted, all weak_ptr objects have their - stored pointers set to 0.

    +

    The weak_ptr class template stores a "weak reference" to an + object that's already managed by a shared_ptr. To access the object, a + weak_ptr can be converted to a shared_ptr using + the shared_ptr constructor or the function + make_shared. When the last shared_ptr to the object + goes away and the object is deleted, the attempt to obtain a shared_ptr +  from the weak_ptr instances that refer to the deleted object will + fail: the constructor will throw an exception of type boost::use_count_is_zero, + and make_shared will return a default constructed (null) shared_ptr.

    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 @@ -20,8 +25,9 @@ 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:

    + often dangerous in multithreaded programs, and sometimes unsafe even + within a single thread (that is, it may invoke undefined behavior.) + Consider, for example, this innocent piece of code:

     shared_ptr<int> p(new int(5));
     weak_ptr<int> q(p);
    @@ -72,7 +78,7 @@ if(shared_ptr<int> r = make_shared(q))
           template<typename Y> weak_ptr & operator=(shared_ptr<Y> const & r); // never throws
     
           void reset();
    -      T * get() const; // never throws; unsafe in multithreaded code!
    +      T * get() const; // never throws; deprecated, will disappear
     
           long use_count() const; // never throws
           bool expired() const; // never throws
    @@ -164,6 +170,11 @@ template<typename Y> weak_ptr & operator=(sh
     				function returns, the pointed-to object may be destroyed by a different thread, 
     				since the weak_ptr doesn't affect its use_count.

    +

    [get is very error-prone. Even single-threaded code may experience + problems, as the returned pointer may be invalidated at any time, for example, + indirectly by a member function of the pointee.

    +

    get is deprecated, and it will disappear in a future + release. Do not use it.]

    use_count

    long use_count() const; // never throws
    @@ -231,8 +242,12 @@ template<typename T, typename U>

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

    Throws: nothing.

    +

    [The current implementation of make_shared can propagate + an exception thrown by the shared_ptr default + constructor, so it doesn't meet the stated requirements. In a future + release, this default constructor will not throw.]


    -

    Revised 12 March 2002

    +

    Revised 29 August 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 From 275cb77378330ebb4a87bf85f12e800543e56693 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 31 Aug 2002 13:04:52 +0000 Subject: [PATCH 128/133] Fixed broken links. [SVN r15123] --- smarttests.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smarttests.htm b/smarttests.htm index 84fd16e..04a4381 100644 --- a/smarttests.htm +++ b/smarttests.htm @@ -22,7 +22,7 @@ a guide for current and future investigations into smart pointer implementation strategies.

    Thanks are due to Dave Abrahams, -Gavin Collings, +Gavin Collings, Greg Colvin and Beman Dawes for test code and trial implementations, the final version of which can be found From f79b8cb7ae8afa34e72ba8d9425b69fc5df2fa8a Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 6 Sep 2002 12:50:02 +0000 Subject: [PATCH 129/133] Tabs removed. [SVN r15175] --- include/boost/detail/shared_count.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 6de061a..cd5ae8f 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -55,7 +55,7 @@ public: virtual char const * what() const throw() { - return "boost::use_count_is_zero"; + return "boost::use_count_is_zero"; } }; From 4ea6decc7d9baa2944ccf4738c9b30a5db472c21 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 9 Sep 2002 17:44:33 +0000 Subject: [PATCH 130/133] scoped_ptr::reset changed to copy+swap (problem reported by Thomas Witt) [SVN r15239] --- include/boost/scoped_ptr.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/boost/scoped_ptr.hpp b/include/boost/scoped_ptr.hpp index 738ad1b..589bd36 100644 --- a/include/boost/scoped_ptr.hpp +++ b/include/boost/scoped_ptr.hpp @@ -61,10 +61,9 @@ public: void reset(T * p = 0) // never throws { - if (ptr != p) + if(ptr != p) { - checked_delete(ptr); - ptr = p; + this_type(p).swap(*this); } } From 0f05f41306c361298cbf9f6493a598507b4491e8 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 16 Sep 2002 15:26:52 +0000 Subject: [PATCH 131/133] Documentation fixes (reflecting Dave Abrahams' comments) [SVN r15382] --- scoped_array.htm | 212 ++++++++++++++------------------ shared_array.htm | 313 ++++++++++++++++++++--------------------------- shared_ptr.htm | 36 +++--- 3 files changed, 242 insertions(+), 319 deletions(-) diff --git a/scoped_array.htm b/scoped_array.htm index 4df98a9..834e0d2 100644 --- a/scoped_array.htm +++ b/scoped_array.htm @@ -1,53 +1,38 @@ - - - - -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 {
    +	
    +		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 {
     
    @@ -59,7 +44,7 @@ pointed to. T must meet the smart pointer
     
           void reset(T * p = 0); // never throws
     
    -      T & operator[](std::size_t i) const; // never throws
    +      T & operator[](std::ptrdiff_t i) const; // never throws
           T * get() const; // never throws
          
           void swap(scoped_array & b); // never throws
    @@ -68,78 +53,59 @@ pointed to. T must meet the smart pointer
       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.

    - - - +

    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::ptrdiff_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/shared_array.htm b/shared_array.htm index 3319553..7b904e9 100644 --- a/shared_array.htm +++ b/shared_array.htm @@ -1,47 +1,35 @@ - - - - -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 {
    +	
    +		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 {
     
    @@ -78,147 +66,114 @@ pointed to. T must meet the smart pointer
       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>
    +		

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

    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.

    - - - +

    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 index 72c63f3..dce72c4 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -19,9 +19,9 @@ 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.

    + object, typically with a 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 @@ -29,11 +29,11 @@

    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 +

    Because the implementation uses reference counting, cycles of shared_ptr instances + will not be reclaimed. 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 @@ -148,10 +148,11 @@ void bad() }

    [It might be convenient to relax the requirements on shared_ptr's - signature, allowing an additional, defaulted, template parameter. This would - help in detecting possible ODR violations. On the other hand, using shared_ptr - as an argument to a template template parameter requires an exact - signature match.]

    + signature, allowing an additional, defaulted, template parameter; the parameter + can encode the threading model, for example. This would help in detecting + possible ODR violations. On the other hand, using shared_ptr as + an argument to a template template parameter requires an exact signature + match.]

    Members

    element_type

    typedef T element_type;
    @@ -229,16 +230,17 @@ void bad()
    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. + constructor and destructor of D must not throw. The expression d2(p), + where d2 is a copy of d, 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.

    + d2(p) is invoked, where d2 is the stored copy of + d.

    [Custom deallocators allow a factory function returning a shared_ptr to insulate the user from its memory allocation strategy. Since the deallocator @@ -647,7 +649,7 @@ int * p = a.release(); implementation or a linked list implementation, or some other specific implementation. This is not the intent.


    -

    Revised +

    Revised 23 July 2002

    Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. Copyright 2002 Peter Dimov. Permission to copy, use, modify, sell and From 024f918b867168d42a0cf041b2fd5dbe17c0e870 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 17 Sep 2002 13:59:17 +0000 Subject: [PATCH 132/133] More documentation fixes reflecting Dave Abrahams' comments [SVN r15411] --- scoped_ptr.htm | 309 +++++++++++++++++---------------------- shared_array.htm | 14 +- shared_ptr.htm | 38 +++-- smart_ptr.htm | 367 +++++++++++++++++++++-------------------------- 4 files changed, 329 insertions(+), 399 deletions(-) diff --git a/scoped_ptr.htm b/scoped_ptr.htm index ec0057d..a301fa6 100644 --- a/scoped_ptr.htm +++ b/scoped_ptr.htm @@ -1,51 +1,38 @@ - - - - -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 {
    +	
    +		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.

    +

    scoped_ptr cannot be used in C++ Standard Library + containers. Use shared_ptr if you need + a smart pointer that can.

    +

    scoped_ptr 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 {
     
    @@ -53,7 +40,7 @@ pointed to. T must meet the smart pointer
          typedef T element_type;
     
          explicit scoped_ptr(T * p = 0); // never throws
    -     ~scoped_ptr(); // never throws
    +     ~scoped_ptr(); // never throws
     
          void reset(T * p = 0); // never throws
     
    @@ -67,75 +54,59 @@ pointed to. T must meet the smart pointer
       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>
    +		

    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
    +

    Destroys the object pointed to by the stored pointer, if any, as if by using delete + this->get().

    +

    + 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"; } };
    +struct Shoe { ~Shoe() { std::cout << "Buckle my shoe\n"; } };
     
     class MyClass {
         boost::scoped_ptr<int> ptr;
    @@ -151,67 +122,55 @@ void main()
         std::cout << my_instance.add_one() << '\n';
         std::cout << my_instance.add_one() << '\n';
     }
    -
    - -

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

    - -
    -
    1
    +		
    +

    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.

    - - - +
    +

    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. When reading source code, it is valuable to be able to draw + conclusions about program behavior based on the types being used. If scoped_ptr + had a release() member, it would become possible to transfer ownership out of + its scope, weakening its role as a way of limiting resource lifetime to a given + scope. Use std::auto_ptr where transfer of ownership is + required. (supplied by Dave Abrahams)

    +
    +

    Revised + 17 September 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_array.htm b/shared_array.htm index 7b904e9..52c58e6 100644 --- a/shared_array.htm +++ b/shared_array.htm @@ -15,13 +15,13 @@ 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 +

    Normally, a shared_array cannot correctly hold a pointer to an object + that has been allocated with the non-array form of new. See + shared_ptr for that usage.

    +

    Because the implementation uses reference counting, cycles of shared_array + instances will not be reclaimed. 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.

    diff --git a/shared_ptr.htm b/shared_ptr.htm index dce72c4..291005f 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -150,9 +150,12 @@ void bad()

    [It might be convenient to relax the requirements on shared_ptr's signature, allowing an additional, defaulted, template parameter; the parameter can encode the threading model, for example. This would help in detecting - possible ODR violations. On the other hand, using shared_ptr as - an argument to a template template parameter requires an exact signature - match.]

    + possible ODR violations.

    +

    On the other hand, using shared_ptr as an argument to + a template template parameter requires an exact signature match. Metaprogramming + experts tend to deemphasize template template parameters as they are too + inflexible, but the alternative is typically an std::allocator::rebind-type + "hack".]

    Members

    element_type

    typedef T element_type;
    @@ -229,18 +232,18 @@ void bad() pointer users.]

    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 d2(p), - where d2 is a copy of d, must be well-formed, - must not invoke undefined behavior, and must not throw exceptions. +

    Requirements: p must be convertible to T *. D + must be CopyConstructible. 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, - d2(p) is invoked, where d2 is the stored copy of - d.

    +

    Notes: When the the time comes to delete the object pointed to by p, + the stored copy of d is invoked with the stored copy of p + as an argument.

    [Custom deallocators allow a factory function returning a shared_ptr to insulate the user from its memory allocation strategy. Since the deallocator @@ -311,9 +314,10 @@ template<typename Y> shared_ptr & operator=(shared_ptr<Y> const 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:

    +

    Notes: The use count updates caused by the temporary object construction + and destruction are not considered observable side effects, and the + implementation is free to meet the effects (and the implied guarantees) via + different means, without creating a temporary. In particular, in the example:

     shared_ptr<int> p(new int);
     shared_ptr<void> q(p);
    @@ -322,6 +326,12 @@ q = p;
     

    both assignments may be no-ops.

    +

    [Some experts consider the note to be redundant, as it appears to essentially + mirror the "as if" rile. However, experience suggests that when C++ code is + used to describe effects, it is often misinterpreted as required + implementation. In addition, it is not entirely clear whether the "as if" rule + actually applies here, so it's better to be explicit about the possible + optimizations.]

    reset

    void reset();
    @@ -649,7 +659,7 @@ int * p = a.release(); implementation or a linked list implementation, or some other specific implementation. This is not the intent.


    -

    Revised +

    Revised 23 July 2002

    Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. Copyright 2002 Peter Dimov. Permission to copy, use, modify, sell and diff --git a/smart_ptr.htm b/smart_ptr.htm index 1e045f1..9e5357a 100644 --- a/smart_ptr.htm +++ b/smart_ptr.htm @@ -1,207 +1,168 @@ - - - - -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 + 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.

    - - - +

    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.

    + From 9dcbc46225216a2e7bc35b5cca263357f5ead7d7 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 18 Sep 2002 13:00:38 +0000 Subject: [PATCH 133/133] Minor fix [SVN r15437] --- scoped_ptr.htm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scoped_ptr.htm b/scoped_ptr.htm index a301fa6..d684b6b 100644 --- a/scoped_ptr.htm +++ b/scoped_ptr.htm @@ -22,9 +22,9 @@

    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.

    -

    scoped_ptr cannot be used in C++ Standard Library - containers. Use shared_ptr if you need - a smart pointer that can.

    +

    scoped_ptr cannot be used in C++ Standard Library containers. + Use shared_ptr if you need a smart pointer + that can.

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

    @@ -160,10 +160,10 @@ Buckle my shoe

    Q. Why doesn't scoped_ptr have a release() member?
    A. When reading source code, it is valuable to be able to draw conclusions about program behavior based on the types being used. If scoped_ptr - had a release() member, it would become possible to transfer ownership out of - its scope, weakening its role as a way of limiting resource lifetime to a given - scope. Use std::auto_ptr where transfer of ownership is - required. (supplied by Dave Abrahams)

    + had a release() member, it would become possible to transfer ownership of the + held pointer, weakening its role as a way of limiting resource lifetime to a + given context. Use std::auto_ptr where transfer of ownership + is required. (supplied by Dave Abrahams)


    Revised 17 September 2002