From 468c41041b3d7ec0394cea52e3c24b7ba90743f7 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 7 Jul 2000 16:04:40 +0000 Subject: [PATCH 01/29] 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 02/29] 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 03/29] 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 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 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 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 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 04/29] 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 05/29] 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 06/29] 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 07/29] 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 08/29] 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 09/29] 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 10/29] 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 11/29] 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 12/29] 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 13/29] 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 14/29] 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 15/29] 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 16/29] 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 17/29] 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 18/29] 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 19/29] 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 20/29] 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 21/29] 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 22/29] 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 23/29] 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 24/29] 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 25/29] 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 26/29] 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 27/29] 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 28/29] 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 29/29] 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