// 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 // 19 Oct 00 Make shared_ptr ctor from auto_ptr explicit. (Robert Vugts) // 24 Jul 00 Change throw() to // never throws. See lib guidelines // Exception-specification rationale. (Beman Dawes) // 22 Jun 00 Remove #if continuations to fix GCC 2.95.2 problem (Beman Dawes) // 1 Feb 00 Additional shared_ptr BOOST_NO_MEMBER_TEMPLATES workarounds // (Dave Abrahams) // 31 Dec 99 Condition tightened for no member template friend workaround // (Dave Abrahams) // 30 Dec 99 Moved BOOST_NMEMBER_TEMPLATES compatibility code to config.hpp // (Dave Abrahams) // 30 Nov 99 added operator ==, operator !=, and std::swap and std::less // specializations for shared types (Darin Adler) // 11 Oct 99 replaced op[](int) with op[](std::size_t) (Ed Brey, Valentin // Bonnard), added shared_ptr workaround for no member template // friends (Matthew Langston) // 25 Sep 99 added shared_ptr::swap and shared_array::swap (Luis Coelho). // 20 Jul 99 changed name to smart_ptr.hpp, #include , // #include and use boost::noncopyable // 17 May 99 remove scoped_array and shared_array operator*() as // unnecessary (Beman Dawes) // 14 May 99 reorder code so no effects when bad_alloc thrown (Abrahams/Dawes) // 13 May 99 remove certain throw() specifiers to avoid generated try/catch // code cost (Beman Dawes) // 11 May 99 get() added, conversion to T* placed in macro guard (Valentin // Bonnard, Dave Abrahams, and others argued for elimination // of the automatic conversion) // 28 Apr 99 #include fix (Valentin Bonnard) // 28 Apr 99 rename transfer() to share() for clarity (Dave Abrahams) // 28 Apr 99 remove unsafe shared_array template conversions(Valentin Bonnard) // 28 Apr 99 p(r) changed to p(r.px) for clarity (Dave Abrahams) // 21 Apr 99 reset() self assignment fix (Valentin Bonnard) // 21 Apr 99 dispose() provided to improve clarity (Valentin Bonnard) // 27 Apr 99 leak when new throws fixes (Dave Abrahams) // 21 Oct 98 initial Version (Greg Colvin/Beman Dawes) #ifndef BOOST_SMART_PTR_HPP #define BOOST_SMART_PTR_HPP #include // for broken compiler workarounds #include // for std::size_t #include // for std::auto_ptr #include // for std::swap #include // for boost::noncopyable #include // for std::less #include #include namespace boost { // scoped_ptr --------------------------------------------------------------// // scoped_ptr mimics a built-in pointer except that it guarantees deletion // of the object pointed to, either on destruction of the scoped_ptr or via // an explicit reset(). scoped_ptr is a simple solution for simple needs; // see shared_ptr (below) or std::auto_ptr if your needs are more complex. template class scoped_ptr : noncopyable { T* ptr; public: typedef T element_type; explicit scoped_ptr( T* p=0 ) : ptr(p) {} // never throws ~scoped_ptr() { delete ptr; } void reset( T* p=0 ) { if ( ptr != p ) { delete ptr; ptr = p; } } T& operator*() const { return *ptr; } // never throws T* operator->() const { return ptr; } // never throws T* get() const { return ptr; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! operator T*() const { return ptr; } // never throws #endif }; // scoped_ptr // scoped_array ------------------------------------------------------------// // scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to // is guaranteed, either on destruction of the scoped_array or via an explicit // reset(). See shared_array or std::vector if your needs are more complex. template class scoped_array : noncopyable { T* ptr; public: typedef T element_type; explicit scoped_array( T* p=0 ) : ptr(p) {} // never throws ~scoped_array() { delete [] ptr; } void reset( T* p=0 ) { if ( ptr != p ) {delete [] ptr; ptr=p;} } T* get() const { return ptr; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! operator T*() const { return ptr; } // never throws #else T& operator[](std::size_t i) const { return ptr[i]; } // never throws #endif }; // scoped_array // shared_ptr --------------------------------------------------------------// // An enhanced relative of scoped_ptr with reference counted copy semantics. // The object pointed to is deleted when the last shared_ptr pointing to it // is destroyed or reset. #if defined(BOOST_MSVC6_MEMBER_TEMPLATES) namespace detail { template class msvc6_member_templates_base {}; } #endif template class shared_ptr #if defined(BOOST_MSVC6_MEMBER_TEMPLATES) : public detail::msvc6_member_templates_base #endif { 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) : 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_AUTO_PTR) #if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES) template explicit shared_ptr(std::auto_ptr& r) #else explicit shared_ptr(std::auto_ptr& r) #endif { pn = new long(1); // may throw px = r.release(); // fix: moved here to stop leak if new throws } #if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES) template shared_ptr& operator=(std::auto_ptr& r) #else shared_ptr& operator=(std::auto_ptr& r) #endif { // 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 // BOOST_NO_AUTO_PTR #if !defined( BOOST_NO_MEMBER_TEMPLATES ) template shared_ptr(const shared_ptr& r) : px(r.px) { // never throws ++*(pn = r.pn); } template shared_ptr& operator=(const shared_ptr& r) { share(r.px,r.pn); return *this; } #elif defined(BOOST_MSVC6_MEMBER_TEMPLATES) template shared_ptr(const detail::msvc6_member_templates_base& r): px(static_cast&>(r).px) { ++*(pn = static_cast&>(r).pn); } template shared_ptr& operator=(const detail::msvc6_member_templates_base& r) { share(static_cast&>(r).px,static_cast&>(r).pn); return *this; } #endif // BOOST_NO_MEMBER_TEMPLATES 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 { return *px; } // never throws T* operator->() const { return px; } // never throws T* get() const { return px; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! operator T*() const { return px; } // never throws #endif long use_count() const { return *pn; } // never throws bool unique() const { return *pn == 1; } // never throws void swap(shared_ptr& other) // never throws { std::swap(px,other.px); std::swap(pn,other.pn); } // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. (Matthew Langston) // Don't split this line into two; that causes problems for some GCC 2.95.2 builds #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) private: #endif T* px; // contained pointer long* pn; // ptr to reference counter // Don't split this line into two; that causes problems for some GCC 2.95.2 builds #if !defined( BOOST_NO_MEMBER_TEMPLATES ) && !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) template friend class shared_ptr; #endif void dispose() { if (--*pn == 0) { 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 #if defined(BOOST_MSVC6_MEMBER_TEMPLATES) : public detail::msvc6_member_templates_base #endif { 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) : px(r.px) // never throws { ++*(pn = r.pn); } ~shared_array() { dispose(); } shared_array& operator=(const shared_array& r) { share(r.px,r.pn); return *this; } #if !defined( BOOST_NO_MEMBER_TEMPLATES ) template shared_array(const shared_array& r) : px(r.px) { // never throws BOOST_STATIC_ASSERT((is_same::value || is_same::value || is_same::value)); ++*(pn = r.pn); } template shared_array& operator=(const shared_array& r) { BOOST_STATIC_ASSERT((is_same::value || is_same::value || is_same::value)); share(r.px,r.pn); return *this; } #elif defined(BOOST_MSVC6_MEMBER_TEMPLATES) template shared_array(const detail::msvc6_member_templates_base& r): px(static_cast&>(r).px) { BOOST_STATIC_ASSERT((is_same::value || is_same::value || is_same::value)); ++*(pn = static_cast&>(r).pn); } template shared_array& operator=(const detail::msvc6_member_templates_base& r) { BOOST_STATIC_ASSERT((is_same::value || is_same::value || is_same::value)); share(static_cast&>(r).px,static_cast&>(r).pn); return *this; } #endif // BOOST_NO_MEMBER_TEMPLATES 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 { return px; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! operator T*() const { return px; } // never throws #else T& operator[](std::size_t i) const { return px[i]; } // never throws #endif long use_count() const { return *pn; } // never throws bool unique() const { return *pn == 1; } // never throws void swap(shared_array& other) // never throws { std::swap(px,other.px); std::swap(pn,other.pn); } #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) private: #endif T* px; // contained pointer long* pn; // ptr to reference counter #if !defined( BOOST_NO_MEMBER_TEMPLATES ) && !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) template friend class shared_array; #endif void dispose() { if (--*pn == 0) { delete [] px; delete pn; } } void share(T* rpx, long* rpn) { if (pn != rpn) { dispose(); px = rpx; ++*(pn = rpn); } } }; // 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