mirror of
				https://github.com/boostorg/smart_ptr.git
				synced 2025-10-27 22:01:45 +01:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			boost-1.67
			...
			boost-1.22
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | a59fb9bccd | 
							
								
								
									
										
											BIN
										
									
								
								gccspeed.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gccspeed.gif
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 6.4 KiB | 
							
								
								
									
										398
									
								
								include/boost/smart_ptr.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										398
									
								
								include/boost/smart_ptr.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,398 @@ | ||||
| //  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 | ||||
| //  21 May 01  Require complete type where incomplete type is unsafe. | ||||
| //             (suggested by Vladimir Prus) | ||||
| //  21 May 01  operator= fails if operand transitively owned by *this, as in a | ||||
| //             linked list (report by Ken Johnson, fix by Beman Dawes) | ||||
| //  21 Jan 01  Suppress some useless warnings with MSVC (David Abrahams) | ||||
| //  19 Oct 00  Make shared_ptr ctor from auto_ptr explicit. (Robert Vugts)  | ||||
| //  24 Jul 00  Change throw() to // never throws.  See lib guidelines | ||||
| //             Exception-specification rationale. (Beman Dawes) | ||||
| //  22 Jun 00  Remove #if continuations to fix GCC 2.95.2 problem (Beman Dawes) | ||||
| //   1 Feb 00  Additional shared_ptr BOOST_NO_MEMBER_TEMPLATES workarounds | ||||
| //             (Dave Abrahams) | ||||
| //  31 Dec 99  Condition tightened for no member template friend workaround | ||||
| //             (Dave Abrahams) | ||||
| //  30 Dec 99  Moved BOOST_NMEMBER_TEMPLATES compatibility code to config.hpp | ||||
| //             (Dave Abrahams) | ||||
| //  30 Nov 99  added operator ==, operator !=, and std::swap and std::less | ||||
| //             specializations for shared types (Darin Adler) | ||||
| //  11 Oct 99  replaced op[](int) with op[](std::size_t) (Ed Brey, Valentin | ||||
| //             Bonnard), added shared_ptr workaround for no member template | ||||
| //             friends (Matthew Langston) | ||||
| //  25 Sep 99  added shared_ptr::swap and shared_array::swap (Luis Coelho). | ||||
| //  20 Jul 99  changed name to smart_ptr.hpp, #include <boost/config.hpp>, | ||||
| //             #include <boost/utility.hpp> and use boost::noncopyable | ||||
| //  17 May 99  remove scoped_array and shared_array operator*() as | ||||
| //             unnecessary (Beman Dawes) | ||||
| //  14 May 99  reorder code so no effects when bad_alloc thrown (Abrahams/Dawes) | ||||
| //  13 May 99  remove certain throw() specifiers to avoid generated try/catch | ||||
| //             code cost (Beman Dawes) | ||||
| //  11 May 99  get() added, conversion to T* placed in macro guard (Valentin | ||||
| //             Bonnard, Dave Abrahams, and others argued for elimination | ||||
| //             of the automatic conversion) | ||||
| //  28 Apr 99  #include <memory> fix (Valentin Bonnard) | ||||
| //  28 Apr 99  rename transfer() to share() for clarity (Dave Abrahams) | ||||
| //  28 Apr 99  remove unsafe shared_array template conversions(Valentin Bonnard) | ||||
| //  28 Apr 99  p(r) changed to p(r.px) for clarity (Dave Abrahams) | ||||
| //  21 Apr 99  reset() self assignment fix (Valentin Bonnard) | ||||
| //  21 Apr 99  dispose() provided to improve clarity (Valentin Bonnard) | ||||
| //  27 Apr 99  leak when new throws fixes (Dave Abrahams) | ||||
| //  21 Oct 98  initial Version (Greg Colvin/Beman Dawes) | ||||
|  | ||||
| #ifndef BOOST_SMART_PTR_HPP | ||||
| #define BOOST_SMART_PTR_HPP | ||||
|  | ||||
| #include <boost/config.hpp>   // for broken compiler workarounds | ||||
| #include <cstddef>            // for std::size_t | ||||
| #include <memory>             // for std::auto_ptr | ||||
| #include <algorithm>          // for std::swap | ||||
| #include <boost/utility.hpp>  // for boost::noncopyable, checked_delete, checked_array_delete | ||||
| #include <functional>         // for std::less | ||||
| #include <boost/static_assert.hpp> // for BOOST_STATIC_ASSERT | ||||
|  | ||||
| #ifdef BOOST_MSVC  // moved here to work around VC++ compiler crash | ||||
| # pragma warning(push) | ||||
| # pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation | ||||
| #endif     | ||||
|  | ||||
| namespace boost { | ||||
|  | ||||
| //  scoped_ptr  --------------------------------------------------------------// | ||||
|  | ||||
| //  scoped_ptr mimics a built-in pointer except that it guarantees deletion | ||||
| //  of the object pointed to, either on destruction of the scoped_ptr or via | ||||
| //  an explicit reset().  scoped_ptr is a simple solution for simple needs; | ||||
| //  see shared_ptr (below) or std::auto_ptr if your needs are more complex. | ||||
|  | ||||
| template<typename T> class scoped_ptr : noncopyable { | ||||
|  | ||||
|   T* ptr; | ||||
|  | ||||
|  public: | ||||
|   typedef T element_type; | ||||
|  | ||||
|   explicit scoped_ptr( T* p=0 ) : ptr(p) {}  // never throws | ||||
|   ~scoped_ptr()                 { checked_delete(ptr); } | ||||
|   void reset( T* p=0 )          { if ( ptr != p ) { checked_delete(ptr); ptr = p; } } | ||||
|   T& operator*() const          { return *ptr; }  // never throws | ||||
|   T* operator->() const         { return ptr; }  // never throws | ||||
|   T* get() const                { return ptr; }  // never throws | ||||
| #ifdef BOOST_SMART_PTR_CONVERSION | ||||
|   // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! | ||||
|   operator T*() const           { return ptr; }  // never throws  | ||||
| #endif | ||||
|   };  // scoped_ptr | ||||
|  | ||||
| //  scoped_array  ------------------------------------------------------------// | ||||
|  | ||||
| //  scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to | ||||
| //  is guaranteed, either on destruction of the scoped_array or via an explicit | ||||
| //  reset(). See shared_array or std::vector if your needs are more complex. | ||||
|  | ||||
| template<typename T> class scoped_array : noncopyable { | ||||
|  | ||||
|   T* ptr; | ||||
|  | ||||
|  public: | ||||
|   typedef T element_type; | ||||
|  | ||||
|   explicit scoped_array( T* p=0 ) : ptr(p) {}  // never throws | ||||
|   ~scoped_array()                    { checked_array_delete(ptr); } | ||||
|  | ||||
|   void reset( T* p=0 )               { if ( ptr != p ) | ||||
|                                          {checked_array_delete(ptr); ptr=p;} } | ||||
|  | ||||
|   T* get() const                     { return ptr; }  // never throws | ||||
| #ifdef BOOST_SMART_PTR_CONVERSION | ||||
|   // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! | ||||
|   operator T*() const                { return ptr; }  // never throws | ||||
| #else  | ||||
|   T& operator[](std::size_t i) const { return ptr[i]; }  // never throws | ||||
| #endif | ||||
|   };  // scoped_array | ||||
|  | ||||
| //  shared_ptr  --------------------------------------------------------------// | ||||
|  | ||||
| //  An enhanced relative of scoped_ptr with reference counted copy semantics. | ||||
| //  The object pointed to is deleted when the last shared_ptr pointing to it | ||||
| //  is destroyed or reset. | ||||
|  | ||||
| template<typename T> class shared_ptr { | ||||
|   public: | ||||
|    typedef T element_type; | ||||
|  | ||||
|    explicit shared_ptr(T* p =0) : px(p) { | ||||
|       try { pn = new long(1); }  // fix: prevent leak if new throws | ||||
|       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 ) | ||||
|    template<typename Y> | ||||
|       shared_ptr(const shared_ptr<Y>& r) : px(r.px) {  // never throws  | ||||
|          ++*(pn = r.pn);  | ||||
|       } | ||||
| #ifndef BOOST_NO_AUTO_PTR | ||||
|    template<typename Y> | ||||
|       explicit shared_ptr(std::auto_ptr<Y>& r) {  | ||||
|          pn = new long(1); // may throw | ||||
|          px = r.release(); // fix: moved here to stop leak if new throws | ||||
|       } | ||||
| #endif  | ||||
|  | ||||
|    template<typename Y> | ||||
|       shared_ptr& operator=(const shared_ptr<Y>& r) {  | ||||
|          share(r.px,r.pn); | ||||
|          return *this; | ||||
|       } | ||||
|  | ||||
| #ifndef BOOST_NO_AUTO_PTR | ||||
|    template<typename Y> | ||||
|       shared_ptr& operator=(std::auto_ptr<Y>& r) { | ||||
|          // code choice driven by guarantee of "no effect if new throws" | ||||
|          if (*pn == 1) { checked_delete(px); } | ||||
|          else { // allocate new reference counter | ||||
|            long * tmp = new long(1); // may throw | ||||
|            --*pn; // only decrement once danger of new throwing is past | ||||
|            pn = tmp; | ||||
|          } // allocate new reference counter | ||||
|          px = r.release(); // fix: moved here so doesn't leak if new throws  | ||||
|          return *this; | ||||
|       } | ||||
| #endif | ||||
| #else | ||||
| #ifndef BOOST_NO_AUTO_PTR | ||||
|       explicit shared_ptr(std::auto_ptr<T>& 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<T>& r) { | ||||
|          // code choice driven by guarantee of "no effect if new throws" | ||||
|          if (*pn == 1) { checked_delete(px); } | ||||
|          else { // allocate new reference counter | ||||
|            long * tmp = new long(1); // may throw | ||||
|            --*pn; // only decrement once danger of new throwing is past | ||||
|            pn = tmp; | ||||
|          } // allocate new reference counter | ||||
|          px = r.release(); // fix: moved here so doesn't leak if new throws  | ||||
|          return *this; | ||||
|       } | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|    void reset(T* p=0) { | ||||
|       if ( px == p ) return;  // fix: self-assignment safe | ||||
|       if (--*pn == 0) { checked_delete(px); } | ||||
|       else { // allocate new reference counter | ||||
|         try { pn = new long; }  // fix: prevent leak if new throws | ||||
|         catch (...) { | ||||
|           ++*pn;  // undo effect of --*pn above to meet effects guarantee  | ||||
|           checked_delete(p); | ||||
|           throw; | ||||
|         } // catch | ||||
|       } // allocate new reference counter | ||||
|       *pn = 1; | ||||
|       px = p; | ||||
|    } // reset | ||||
|  | ||||
|    T& operator*() const          { return *px; }  // never throws | ||||
|    T* operator->() const         { return px; }  // never throws | ||||
|    T* get() const                { return px; }  // never throws | ||||
|  #ifdef BOOST_SMART_PTR_CONVERSION | ||||
|    // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! | ||||
|    operator T*() const           { return px; }  // never throws  | ||||
|  #endif | ||||
|  | ||||
|    long use_count() const        { return *pn; }  // never throws | ||||
|    bool unique() const           { return *pn == 1; }  // never throws | ||||
|  | ||||
|    void swap(shared_ptr<T>& 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_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<typename Y> friend class shared_ptr; | ||||
| #endif | ||||
|  | ||||
|    void dispose() { if (--*pn == 0) { checked_delete(px); delete pn; } } | ||||
|  | ||||
|    void share(T* rpx, long* rpn) { | ||||
|       if (pn != rpn) { // Q: why not px != rpx? A: fails when both == 0 | ||||
|          ++*rpn; // done before dispose() in case rpn transitively | ||||
|                  // dependent on *this (bug reported by Ken Johnson) | ||||
|          dispose(); | ||||
|          px = rpx; | ||||
|          pn = rpn; | ||||
|       } | ||||
|    } // share | ||||
| };  // shared_ptr | ||||
|  | ||||
| template<typename T, typename U> | ||||
|   inline bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b) | ||||
|     { return a.get() == b.get(); } | ||||
|  | ||||
| template<typename T, typename U> | ||||
|   inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b) | ||||
|     { return a.get() != b.get(); } | ||||
|  | ||||
| //  shared_array  ------------------------------------------------------------// | ||||
|  | ||||
| //  shared_array extends shared_ptr to arrays. | ||||
| //  The array pointed to is deleted when the last shared_array pointing to it | ||||
| //  is destroyed or reset. | ||||
|  | ||||
| template<typename T> class shared_array { | ||||
|   public: | ||||
|    typedef T element_type; | ||||
|  | ||||
|    explicit shared_array(T* p =0) : px(p) { | ||||
|       try { pn = new long(1); }  // fix: prevent leak if new throws | ||||
|       catch (...) { checked_array_delete(p); throw; }  | ||||
|    } | ||||
|  | ||||
|    shared_array(const shared_array& r) : px(r.px)  // never throws | ||||
|       { ++*(pn = r.pn); } | ||||
|  | ||||
|    ~shared_array() { dispose(); } | ||||
|  | ||||
|    shared_array& operator=(const shared_array& r) { | ||||
|       if (pn != r.pn) { // Q: why not px != r.px? A: fails when both px == 0 | ||||
|          ++*r.pn; // done before dispose() in case r.pn transitively | ||||
|                   // dependent on *this (bug reported by Ken Johnson) | ||||
|          dispose(); | ||||
|          px = r.px; | ||||
|          pn = r.pn; | ||||
|       } | ||||
|       return *this; | ||||
|    } // operator= | ||||
|  | ||||
|    void reset(T* p=0) { | ||||
|       if ( px == p ) return;  // fix: self-assignment safe | ||||
|       if (--*pn == 0) { checked_array_delete(px); } | ||||
|       else { // allocate new reference counter | ||||
|         try { pn = new long; }  // fix: prevent leak if new throws | ||||
|         catch (...) { | ||||
|           ++*pn;  // undo effect of --*pn above to meet effects guarantee  | ||||
|           checked_array_delete(p); | ||||
|           throw; | ||||
|         } // catch | ||||
|       } // allocate new reference counter | ||||
|       *pn = 1; | ||||
|       px = p; | ||||
|    } // reset | ||||
|  | ||||
|    T* get() const                     { return px; }  // never throws | ||||
|  #ifdef BOOST_SMART_PTR_CONVERSION | ||||
|    // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! | ||||
|    operator T*() const                { return px; }  // never throws | ||||
|  #else  | ||||
|    T& operator[](std::size_t i) const { return px[i]; }  // never throws | ||||
|  #endif | ||||
|  | ||||
|    long use_count() const             { return *pn; }  // never throws | ||||
|    bool unique() const                { return *pn == 1; }  // never throws | ||||
|  | ||||
|    void swap(shared_array<T>& other)  // never throws | ||||
|      { std::swap(px,other.px); std::swap(pn,other.pn); } | ||||
|  | ||||
|   private: | ||||
|  | ||||
|    T*     px;     // contained pointer | ||||
|    long*  pn;     // ptr to reference counter | ||||
|  | ||||
|    void dispose() { if (--*pn == 0) { checked_array_delete(px); delete pn; } } | ||||
|  | ||||
| };  // shared_array | ||||
|  | ||||
| template<typename T> | ||||
|   inline bool operator==(const shared_array<T>& a, const shared_array<T>& b) | ||||
|     { return a.get() == b.get(); } | ||||
|  | ||||
| template<typename T> | ||||
|   inline bool operator!=(const shared_array<T>& a, const shared_array<T>& b) | ||||
|     { return a.get() != b.get(); } | ||||
|  | ||||
| } // namespace boost | ||||
|  | ||||
| //  specializations for things in namespace std  -----------------------------// | ||||
|  | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|  | ||||
| namespace std { | ||||
|  | ||||
| // Specialize std::swap to use the fast, non-throwing swap that's provided | ||||
| // as a member function instead of using the default algorithm which creates | ||||
| // a temporary and uses assignment. | ||||
|  | ||||
| template<typename T> | ||||
|   inline void swap(boost::shared_ptr<T>& a, boost::shared_ptr<T>& b) | ||||
|     { a.swap(b); } | ||||
|  | ||||
| template<typename T> | ||||
|   inline void swap(boost::shared_array<T>& a, boost::shared_array<T>& b) | ||||
|     { a.swap(b); } | ||||
|  | ||||
| // Specialize std::less so we can use shared pointers and arrays as keys in | ||||
| // associative collections. | ||||
|  | ||||
| // It's still a controversial question whether this is better than supplying | ||||
| // a full range of comparison operators (<, >, <=, >=). | ||||
|  | ||||
| template<typename T> | ||||
|   struct less< boost::shared_ptr<T> > | ||||
|     : binary_function<boost::shared_ptr<T>, boost::shared_ptr<T>, bool> | ||||
|   { | ||||
|     bool operator()(const boost::shared_ptr<T>& a, | ||||
|         const boost::shared_ptr<T>& b) const | ||||
|       { return less<T*>()(a.get(),b.get()); } | ||||
|   }; | ||||
|  | ||||
| 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 | ||||
|  | ||||
| #endif  // ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|  | ||||
| #ifdef BOOST_MSVC | ||||
| # pragma warning(pop) | ||||
| #endif     | ||||
|  | ||||
| #endif  // BOOST_SMART_PTR_HPP | ||||
|  | ||||
|  | ||||
							
								
								
									
										38
									
								
								index.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								index.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> | ||||
| <title>Boost Smart Pointer Library</title> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
| <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
|  | ||||
| <table border="1" bgcolor="#007F7F" cellpadding="2"> | ||||
|   <tr> | ||||
|     <td bgcolor="#FFFFFF"><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" width="277" height="86"></td> | ||||
|     <td><a href="../../index.htm"><font face="Arial" color="#FFFFFF"><big>Home</big></font></a></td> | ||||
|     <td><a href="../libraries.htm"><font face="Arial" color="#FFFFFF"><big>Libraries</big></font></a></td> | ||||
|     <td><a href="../../people/people.htm"><font face="Arial" color="#FFFFFF"><big>People</big></font></a></td> | ||||
|     <td><a href="../../more/faq.htm"><font face="Arial" color="#FFFFFF"><big>FAQ</big></font></a></td> | ||||
|     <td><a href="../../more/index.htm"><font face="Arial" color="#FFFFFF"><big>More</big></font></a></td> | ||||
|   </tr> | ||||
| </table> | ||||
| <h1>Smart pointer library</h1> | ||||
| <p>The header smart_ptr.hpp provides four smart pointer classes.  Smart | ||||
| pointers ease the management of memory dynamically allocated with C++ <strong>new</strong> | ||||
| expressions. | ||||
| <ul> | ||||
|   <li><a href="smart_ptr.htm">Documentation</a> (HTML).</li> | ||||
|   <li>Header <a href="../../boost/smart_ptr.hpp">smart_ptr.hpp</a></li> | ||||
|   <li>Test program <a href="smart_ptr_test.cpp">smart_ptr_test.cpp</a>.</li> | ||||
|   <li>Submitted by <a href="../../people/greg_colvin.htm">Greg Colvin</a> and <a href="../../people/beman_dawes.html">Beman | ||||
|     Dawes</a>.</li> | ||||
| </ul> | ||||
| <p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->14 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14885" --> | ||||
| </p> | ||||
|  | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
							
								
								
									
										
											BIN
										
									
								
								msvcspeed.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								msvcspeed.gif
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 6.0 KiB | 
							
								
								
									
										102
									
								
								scoped_array.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								scoped_array.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
| <title>scoped_array</title> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
| <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
|  | ||||
| <h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Class | ||||
| <a name="scoped_array">scoped_array</a></h1> | ||||
| <p>Class <strong>scoped_array</strong> stores a pointer to a dynamically | ||||
| allocated array. (Dynamically allocated arrays are allocated with the C++ <tt>new[]</tt> | ||||
| expression.)   The array pointed to is guaranteed to be deleted, | ||||
| either on destruction of the <strong>scoped_array</strong>, or via an explicit <strong>scoped_array::reset()</strong>.</p> | ||||
| <p>Class<strong> scoped_array</strong> is a simple solution for simple | ||||
| needs. It supplies a basic "resource acquisition is | ||||
| initialization" facility, without shared-ownership or transfer-of-ownership | ||||
| semantics.  Both its name and enforcement of semantics (by being <a href="../utility/utility.htm#class noncopyable">noncopyable</a>) | ||||
| signal its intent to retain ownership solely within the current scope.  By | ||||
| being <a href="../utility/utility.htm#class noncopyable">noncopyable</a>, it is | ||||
| safer than <b>shared_array</b> for pointers which should not be copied.</p> | ||||
| <p>Because <strong>scoped_array</strong> 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.</p> | ||||
| <p>It cannot be used in C++ Standard Library containers.  See <a href="shared_array.htm"><strong>shared_array</strong></a> | ||||
| if <strong>scoped_array</strong> does not meet your needs.</p> | ||||
| <p>Class<strong> scoped_array</strong> cannot correctly hold a pointer to a | ||||
| single object.  See <a href="scoped_ptr.htm"><strong>scoped_ptr</strong></a> | ||||
| for that usage.</p> | ||||
| <p>A C++ Standard Library <strong>vector</strong> is a <strong> </strong>heavier duty alternative to a <strong>scoped_array</strong>.</p> | ||||
| <p>The class is a template parameterized on <tt>T</tt>, the type of the object | ||||
| pointed to.   <tt>T</tt> must meet the smart pointer <a href="smart_ptr.htm#Common requirements">common | ||||
| requirements</a>.</p> | ||||
| <h2>Class scoped_array Synopsis</h2> | ||||
| <pre>#include <<a href="../../boost/smart_ptr.hpp">boost/smart_ptr.hpp</a>> | ||||
| namespace boost { | ||||
|  | ||||
| template<typename T> class scoped_array : <a href="../utility/utility.htm#noncopyable">noncopyable</a> { | ||||
|  | ||||
|  public: | ||||
|    typedef T <a href="#scoped_array_element_type">element_type</a>; | ||||
|  | ||||
|    explicit <a href="#scoped_array_ctor">scoped_array</a>( T* p=0 );  // never throws | ||||
|   <strong> </strong><a href="#scoped_array_~scoped_array">~scoped_array</a>(); | ||||
|  | ||||
|    void <a href="#scoped_array_reset">reset</a>( T* p=0 ); | ||||
|  | ||||
|    T& <a href="#scoped_array_operator[]">operator[]</a>(std::size_t i) const;  // never throws | ||||
|    T* <a href="#scoped_array_get">get</a>() const;  // never throws | ||||
|    }; | ||||
| }</pre> | ||||
| <h2>Class scoped_array Members</h2> | ||||
| <h3>scoped_array <a name="scoped_array_element_type">element_type</a></h3> | ||||
| <pre>typedef T element_type;</pre> | ||||
| <p>Provides the type of the stored pointer.</p> | ||||
| <h3><a name="scoped_array_ctor">scoped_array constructors</a></h3> | ||||
| <pre>explicit scoped_array( T* p=0 );  // never throws</pre> | ||||
| <p>Constructs a <tt>scoped_array</tt>, storing a copy of <tt>p</tt>, which must | ||||
| have been allocated via a C++ <tt>new</tt>[] expression or be 0.</p> | ||||
| <p><b>T</b> is not required be a complete type.  | ||||
| See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p> | ||||
| <h3><a name="scoped_array_~scoped_array">scoped_array destructor</a></h3> | ||||
| <pre>~scoped_array();</pre> | ||||
| <p>Deletes the array pointed to by the stored pointer.  Note that in C++ <tt>delete</tt>[] | ||||
| on a pointer with a value of 0 is harmless.</p> | ||||
| <p>Does not throw exceptions.</p> | ||||
| <h3>scoped_array <a name="scoped_array_reset">reset</a></h3> | ||||
| <pre>void reset( T* p=0 )();</pre> | ||||
| <p>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++ <tt>new[]</tt> expression or be 0.</p> | ||||
| <p>Does not throw exceptions.</p> | ||||
| <h3>scoped_array <a name="scoped_array_operator[]">operator[]</a></h3> | ||||
| <p><tt>T& operator[](std::size_t i) const; // never throws</tt></p> | ||||
| <p>Returns a reference to element <tt>i</tt> of the array pointed to by the | ||||
| stored pointer.</p> | ||||
| <p>Behavior is undefined (and almost certainly undesirable) if <tt>get()==0</tt>, | ||||
| or if <tt>i</tt> is less than 0 or is greater or equal to the number of elements | ||||
| in the array.</p> | ||||
| <h3>scoped_array <a name="scoped_array_get">get</a></h3> | ||||
| <pre>T* get() const;  // never throws</pre> | ||||
| <p><b>T</b> is not required be a complete type.  | ||||
| See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p> | ||||
| <p>Returns the stored pointer.</p> | ||||
| <h2>Class <a name="shared_array_example">scoped_array example</a></h2> | ||||
| <p>[To be supplied. In the meantime, see <a href="smart_ptr_test.cpp">smart_ptr_test.cpp</a>.]</p> | ||||
| <hr> | ||||
| <p>Revised  <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan | ||||
| -->24 May, 2001<!--webbot bot="Timestamp" endspan i-checksum="13964" | ||||
| --> | ||||
| </p> | ||||
| <p><EFBFBD> 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.</p> | ||||
|  | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
							
								
								
									
										153
									
								
								scoped_ptr.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								scoped_ptr.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
| <title>scoped_ptr</title> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
| <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
|  | ||||
| <h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Class | ||||
| <a name="scoped_ptr">scoped_ptr</a></h1> | ||||
| <p>Class <strong>scoped_ptr</strong> stores a pointer to a dynamically allocated | ||||
| object. (Dynamically allocated objects are allocated with the C++ <tt>new</tt> | ||||
| expression.)   The object pointed to is guaranteed to be deleted, | ||||
| either on destruction of the <strong>scoped_ptr</strong>, or via an explicit <strong>scoped_ptr::reset()</strong>.  | ||||
| See <a href="#scoped_ptr_example">example</a>.</p> | ||||
| <p>Class<strong> scoped_ptr</strong> is a simple solution for simple | ||||
| needs.  It supplies a basic "resource acquisition is | ||||
| initialization" facility, without shared-ownership or transfer-of-ownership | ||||
| semantics.  Both its name and enforcement of semantics (by being <a href="../utility/utility.htm#class noncopyable">noncopyable</a>) | ||||
| signal its intent to retain ownership solely within the current scope.  | ||||
| Because it is <a href="../utility/utility.htm#class noncopyable">noncopyable</a>, it is | ||||
| safer than <b>shared_ptr</b> or <b> std::auto_ptr</b> for pointers which should not be | ||||
| copied.</p> | ||||
| <p>Because <strong>scoped_ptr</strong> 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.  (Because of the "complete type" | ||||
| requirement for delete and reset members, they may have one additional function | ||||
| call overhead in certain idioms.  See <a href="#Handle/Body">Handle/Body | ||||
| Idiom</a>.)   </p> | ||||
| <p>Class<strong> scoped_ptr</strong> cannot be used in C++ Standard Library containers.  See <a href="shared_ptr.htm"><strong>shared_ptr</strong></a> | ||||
| or std::auto_ptr if <strong>scoped_ptr</strong> does not meet your needs.</p> | ||||
| <p>Class<strong> scoped_ptr</strong> cannot correctly hold a pointer to a | ||||
| dynamically allocated array.  See <a href="scoped_array.htm"><strong>scoped_array</strong></a> | ||||
| for that usage.</p> | ||||
| <p>The class is a template parameterized on <tt>T</tt>, the type of the object | ||||
| pointed to.   <tt>T</tt> must meet the smart pointer <a href="smart_ptr.htm#Common requirements">common | ||||
| requirements</a>.</p> | ||||
| <h2>Class scoped_ptr Synopsis</h2> | ||||
| <pre>#include <<a href="../../boost/smart_ptr.hpp">boost/smart_ptr.hpp</a>> | ||||
| namespace boost { | ||||
|  | ||||
| template<typename T> class scoped_ptr : <a href="../utility/utility.htm#class noncopyable">noncopyable</a> { | ||||
|  | ||||
|  public: | ||||
|    typedef T <a href="#scoped_ptr_element_type">element_type</a>; | ||||
|  | ||||
|    explicit <a href="#scoped_ptr_ctor">scoped_ptr</a>( T* p=0 );  // never throws | ||||
|   <strong> </strong><a href="#scoped_ptr_~scoped_ptr">~scoped_ptr</a>(); | ||||
|  | ||||
|    void <a href="#scoped_ptr_reset">reset</a>( T* p=0 ); | ||||
|  | ||||
|    T& <a href="#scoped_ptr_operator*">operator*</a>() const;  // never throws | ||||
|    T* <a href="#scoped_ptr_operator->">operator-></a>() const;  // never throws | ||||
|    T* <a href="#scoped_ptr_get">get</a>() const;  // never throws | ||||
|    }; | ||||
| }</pre> | ||||
| <h2>Class scoped_ptr Members</h2> | ||||
| <h3>scoped_ptr <a name="scoped_ptr_element_type">element_type</a></h3> | ||||
| <pre>typedef T element_type;</pre> | ||||
| <p>Provides the type of the stored pointer.</p> | ||||
| <h3><a name="scoped_ptr_ctor">scoped_ptr constructors</a></h3> | ||||
| <pre>explicit scoped_ptr( T* p=0 );  // never throws</pre> | ||||
| <p><b>T</b> is not required be a complete type.  | ||||
| See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p> | ||||
| <p>Constructs a <tt>scoped_ptr</tt>, storing a copy of <tt>p</tt>, which must | ||||
| have been allocated via a C++ <tt>new</tt> expression or be 0.</p> | ||||
| <h3><a name="scoped_ptr_~scoped_ptr">scoped_ptr destructor</a></h3> | ||||
| <pre>~scoped_ptr();</pre> | ||||
| <p>Deletes the object pointed to by the stored pointer.  Note that in C++, <tt>delete</tt> | ||||
| on a pointer with a value of 0 is harmless.</p> | ||||
| <p>Does not throw exceptions.</p> | ||||
| <h3>scoped_ptr <a name="scoped_ptr_reset">reset</a></h3> | ||||
| <pre>void reset( T* p=0 );</pre> | ||||
| <p>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++ <tt>new</tt> expression or be 0.</p> | ||||
| <p>Does not throw exceptions.</p> | ||||
| <h3>scoped_ptr <a name="scoped_ptr_operator*">operator*</a></h3> | ||||
| <pre>T& operator*() const;  // never throws</pre> | ||||
| <p>Returns a reference to the object pointed to by the stored pointer.</p> | ||||
| <h3>scoped_ptr <a name="scoped_ptr_operator->">operator-></a> and <a name="scoped_ptr_get">get</a></h3> | ||||
| <pre>T* operator->() const;  // never throws | ||||
| T* get() const;  // never throws</pre> | ||||
| <p><b>T</b> is not required by get() be a complete type.  See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p> | ||||
| <p>Both return the stored pointer.</p> | ||||
| <h2>Class <a name="scoped_ptr_example">scoped_ptr example</a>s</h2> | ||||
| <pre>#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; | ||||
|     }</pre> | ||||
| <p>The example program produces the beginning of a child's nursery rhyme as | ||||
| output:</p> | ||||
| <blockquote> | ||||
|   <pre>1 | ||||
| 2 | ||||
| Buckle my shoe</pre> | ||||
| </blockquote> | ||||
| <h2>Rationale</h2> | ||||
| <p>The primary reason to use <b> scoped_ptr</b> rather than <b> auto_ptr</b> 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.</p> | ||||
| <p>A secondary reason to use <b> scoped_ptr</b> is to prevent a later maintenance programmer from adding a function that actually transfers | ||||
| ownership by returning the <b> auto_ptr</b> (because the maintenance programmer saw | ||||
| <b>auto_ptr</b>, and assumed ownership could safely be transferred.) </p> | ||||
| <p>Think of <b>bool</b> vs <b>int</b>.  We all know that under the covers <b> bool</b> is usually | ||||
| just an <b>int</b>.  Indeed, some argued against including <b> bool</b> in the | ||||
| C++ standard because of that.  But by coding <b> bool</b> rather than <b> int</b>, you tell your readers | ||||
| what your intent is.  Same with <b> scoped_ptr</b> - you are signaling intent.</p> | ||||
| <p>It has been suggested that <b>boost::scoped_ptr<T></b> is equivalent to | ||||
| <b>std::auto_ptr<T> const</b>.  Ed Brey pointed out, however, that | ||||
| reset() will not work on a <b>std::auto_ptr<T> const.</b></p> | ||||
| <h2><a name="Handle/Body">Handle/Body</a> Idiom</h2> | ||||
| <p>One common usage of <b>scoped_ptr</b> is to implement a handle/body (also | ||||
| called pimpl) idiom which avoids exposing the body (implementation) in the header | ||||
| file.</p> | ||||
| <p>The <a href="scoped_ptr_example_test.cpp">scoped_ptr_example_test.cpp</a> | ||||
| sample program includes a header file, <a href="scoped_ptr_example.hpp">scoped_ptr_example.hpp</a>, | ||||
| which uses a <b>scoped_ptr<></b> to an incomplete type to hide the | ||||
| implementation.   The | ||||
| instantiation of member functions which require a complete type occurs in the <a href="scoped_ptr_example.cpp">scoped_ptr_example.cpp</a> | ||||
| implementation file.</p> | ||||
| <h2>FAQ</h2> | ||||
| <p><b>Q</b>. Why doesn't <b>scoped_ptr</b> have a release() member?<br> | ||||
| <b>A</b>. Because the whole point of <b>scoped_ptr</b> is to signal intent not | ||||
| to transfer ownership.  Use <b>std::auto_ptr</b> if ownership transfer is | ||||
| required.</p> | ||||
| <hr> | ||||
| <p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B %Y" startspan -->24 May 2001<!--webbot bot="Timestamp" endspan i-checksum="15110" --></p> | ||||
| <p><EFBFBD> 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.</p> | ||||
|  | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
							
								
								
									
										16
									
								
								scoped_ptr_example.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								scoped_ptr_example.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| // Boost scoped_ptr_example implementation file  -----------------------------// | ||||
|  | ||||
| #include "scoped_ptr_example.hpp" | ||||
| #include <iostream> | ||||
|  | ||||
| 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() {} | ||||
							
								
								
									
										21
									
								
								scoped_ptr_example.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								scoped_ptr_example.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| //  Boost scoped_ptr_example header file  ------------------------------------// | ||||
|  | ||||
| #include <boost/smart_ptr.hpp> | ||||
|  | ||||
| //  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 | ||||
| }; | ||||
|  | ||||
							
								
								
									
										10
									
								
								scoped_ptr_example_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								scoped_ptr_example_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
| } | ||||
							
								
								
									
										189
									
								
								shared_array.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								shared_array.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,189 @@ | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
| <title>shared_array</title> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
| <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
|  | ||||
| <h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Class | ||||
| <a name="shared_array">shared_array</a></h1> | ||||
| <p>Class <strong>shared_array</strong> stores a pointer to a dynamically | ||||
| allocated array. (Dynamically allocated arrays are allocated with the C++ <tt>new[]</tt> | ||||
| expression.)   The array pointed to is guaranteed to be deleted, | ||||
| either on destruction of the <strong>shared_array</strong>, on <strong>shared_array::operator=()</strong>, | ||||
| or via an explicit <strong>shared_array::reset()</strong>.  See <a href="#shared_array_example">example</a>.</p> | ||||
| <p>Class<strong> shared_array</strong> meets the <strong>CopyConstuctible</strong> | ||||
| and <strong>Assignable</strong> 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 <strong> | ||||
| shared_array</strong> 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.</p> | ||||
| <p>Class<strong> shared_array</strong> cannot correctly hold a pointer to a | ||||
| single object.  See <a href="shared_ptr.htm"><strong>shared_ptr</strong></a> | ||||
| for that usage.</p> | ||||
| <p>Class<strong> shared_array</strong> 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.</p> | ||||
| <p>A C++ Standard Library <strong>vector</strong> is <strong> </strong>a <strong> | ||||
| </strong>heavier duty alternative to a <strong>shared_array</strong>.</p> | ||||
| <p>The class is a template parameterized on <tt>T</tt>, the type of the object | ||||
| pointed to.   <tt>T</tt> must meet the smart pointer <a href="smart_ptr.htm#Common requirements">Common | ||||
| requirements</a>.</p> | ||||
| <h2>Class shared_array Synopsis</h2> | ||||
| <pre>#include <<a href="../../boost/smart_ptr.hpp">boost/smart_ptr.hpp</a>> | ||||
| namespace boost { | ||||
|  | ||||
| template<typename T> class shared_array { | ||||
|  | ||||
|  public: | ||||
|    typedef T <a href="#shared_array_element_type">element_type</a>; | ||||
|  | ||||
|    explicit <a href="#shared_array_ctor">shared_array</a>( T* p=0 ); | ||||
|    <a href="#shared_array_ctor">shared_array</a>( const shared_array& );  // never throws    | ||||
|   <strong> </strong><a href="#shared_array_~shared_array">~shared_array</a>(); | ||||
|  | ||||
|    shared_array& <a href="#shared_array_operator=">operator=</a>( const shared_array& );  // never throws   | ||||
|  | ||||
|    void <a href="#shared_array_reset">reset</a>( T* p=0 ); | ||||
|  | ||||
|    T& <a href="#shared_array_operator[]">operator[]</a>(std::size_t i) const;  // never throws | ||||
|    T* <a href="#shared_array_get">get</a>() const;  // never throws | ||||
|  | ||||
|    long <a href="#shared_array_use_count">use_count</a>() const;  // never throws | ||||
|    bool <a href="#shared_array_unique">unique</a>() const;  // never throws | ||||
|  | ||||
|    void <a href="#shared_array_swap">swap</a>( 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(); } | ||||
| }</pre> | ||||
| <pre>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 </pre> | ||||
| <p>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.<br> | ||||
| <br> | ||||
| Specialization of std::less allows use of shared arrays as keys in C++ | ||||
| Standard Library associative collections.<br> | ||||
| <br> | ||||
| 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).<br> | ||||
| <br> | ||||
| It's still a controversial question whether supplying only std::less is better | ||||
| than supplying a full range of comparison operators (<, >, <=, >=).</p> | ||||
| <p>The current implementation does not supply the specializations if the macro | ||||
| name BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION is defined.</p> | ||||
| <h2>Class shared_array Members</h2> | ||||
| <h3>shared_array <a name="shared_array_element_type">element_type</a></h3> | ||||
| <pre>typedef T element_type;</pre> | ||||
| <p>Provides the type of the stored pointer.</p> | ||||
| <h3><a name="shared_array_ctor">shared_array constructors</a></h3> | ||||
| <pre>explicit shared_array( T* p=0 );</pre> | ||||
| <p>Constructs a <strong>shared_array</strong>, storing a copy of <tt>p</tt>, | ||||
| which must have been allocated via a C++ <tt>new</tt>[] expression or be 0. | ||||
| Afterwards, use_count() is 1 (even if p==0; see <a href="#shared_array_~shared_array">~shared_array</a>).</p> | ||||
| <p>The only exception which may be thrown is <tt>std::bad_alloc</tt>.  If | ||||
| an exception is thrown,  <tt>delete[] p</tt> is called.</p> | ||||
| <pre>shared_array( const shared_array& r);  // never throws</pre> | ||||
| <p>Constructs a <strong>shared_array</strong>, as if by storing a copy of the | ||||
| pointer stored in <strong>r</strong>. Afterwards, <strong>use_count()</strong> | ||||
| for all copies is 1 more than the initial <strong>r.use_count()</strong>.</p> | ||||
| <h3><a name="shared_array_~shared_array">shared_array destructor</a></h3> | ||||
| <pre>~shared_array();</pre> | ||||
| <p>If <strong>use_count()</strong> == 1, deletes the array pointed to by the | ||||
| stored pointer. Otherwise, <strong>use_count()</strong> for any remaining | ||||
| copies is decremented by 1. Note that in C++ <tt>delete</tt>[] on a pointer with | ||||
| a value of 0 is harmless.</p> | ||||
| <p>Does not throw exceptions.</p> | ||||
| <h3>shared_array <a name="shared_array_operator=">operator=</a></h3> | ||||
| <pre>shared_array& operator=( const shared_array& r);  // never throws</pre> | ||||
| <p>First, if <strong>use_count()</strong> == 1, deletes the array pointed to by | ||||
| the stored pointer. Otherwise, <strong>use_count()</strong> for any | ||||
| remaining copies is decremented by 1. Note that in C++ <tt>delete</tt>[] on a | ||||
| pointer with a value of 0 is harmless.</p> | ||||
| <p>Then replaces the contents of <strong>this</strong>, as if by storing a copy | ||||
| of the pointer stored in <strong>r</strong>. Afterwards, <strong>use_count()</strong> | ||||
| for all copies is 1 more than the initial <strong>r.use_count()</strong>. </p> | ||||
| <h3>shared_array <a name="shared_array_reset">reset</a></h3> | ||||
| <pre>void reset( T* p=0 );</pre> | ||||
| <p>First, if <strong>use_count()</strong> == 1, deletes the array pointed to by | ||||
| the stored pointer. Otherwise, <strong>use_count()</strong> for any | ||||
| remaining copies is decremented by 1. Note that in C++  <tt>delete</tt>[] | ||||
| on a pointer with a value of 0 is harmless.</p> | ||||
| <p>Then replaces the contents of <strong>this</strong>, as if by storing a copy | ||||
| of <strong>p</strong>, which must have been allocated via a C++ <tt>new</tt>[] | ||||
| expression or be 0. Afterwards, <strong>use_count()</strong> is 1 (even if p==0; | ||||
| see <a href="#shared_array_~shared_array">~shared_array</a>).</p> | ||||
| <p>The only exception which may be thrown is <tt>std::bad_alloc</tt>.  If | ||||
| an exception is thrown,  <tt>delete[] p</tt> is called.</p> | ||||
| <h3>shared_array <a name="shared_array_operator[]">operator[]</a></h3> | ||||
| <p><tt>T& operator[](std::size_t i) const; // never throws</tt></p> | ||||
| <p>Returns a reference to element <tt>i</tt> of the array pointed to by the | ||||
| stored pointer.</p> | ||||
| <p>Behavior is undefined (and almost certainly undesirable) if <tt>get()==0</tt>, | ||||
| or if <tt>i</tt> is less than 0 or is greater or equal to the number of elements | ||||
| in the array.</p> | ||||
| <h3>shared_array <a name="shared_array_get">get</a></h3> | ||||
| <pre>T* get() const;  // never throws</pre> | ||||
| <p><b>T</b> is not required be a complete type.  | ||||
| See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p> | ||||
| <p>Returns the stored pointer.</p> | ||||
| <h3>shared_array<a name="shared_array_use_count"> use_count</a></h3> | ||||
| <p><tt>long use_count() const; // never throws</tt></p> | ||||
| <p><b>T</b> is not required be a complete type.  | ||||
| See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p> | ||||
| <p>Returns the number of <strong>shared_arrays</strong> sharing ownership of the | ||||
| stored pointer.</p> | ||||
| <h3>shared_array <a name="shared_array_unique">unique</a></h3> | ||||
| <p><tt>bool unique() const; // never throws</tt></p> | ||||
| <p><b>T</b> is not required be a complete type.  | ||||
| See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p> | ||||
| <p>Returns <strong>use_count()</strong> == 1.</p> | ||||
| <h3><a name="shared_array_swap">shared_array swap</a></h3> | ||||
| <p><code>void swap( shared_array<T>& other ) throw()</code></p> | ||||
| <p><b>T</b> is not required be a complete type.  | ||||
| See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p> | ||||
| <p>Swaps the two smart pointers, as if by std::swap.</p> | ||||
| <h2>Class <a name="shared_array_example">shared_array example</a></h2> | ||||
| <p>[To be supplied. In the meantime, see <a href="smart_ptr_test.cpp">smart_ptr_test.cpp</a>.]</p> | ||||
| <hr> | ||||
| <p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->24 May, 2001<!--webbot bot="Timestamp" endspan i-checksum="13964" --> | ||||
| </p> | ||||
| <p><EFBFBD> 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.</p> | ||||
|  | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
							
								
								
									
										243
									
								
								shared_ptr.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								shared_ptr.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,243 @@ | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
| <title>shared_ptr</title> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
| <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
|  | ||||
| <h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Class | ||||
| <a name="shared_ptr">shared_ptr</a></h1> | ||||
| <p>Class <strong>shared_ptr</strong> stores a pointer to a dynamically allocated | ||||
| object. (Dynamically allocated objects are allocated with the C++ <tt>new</tt> | ||||
| expression.)   The object pointed to is guaranteed to be deleted when | ||||
| the last <strong>shared_ptr</strong> pointing to it is deleted or reset.  | ||||
| See <a href="#shared_ptr_example">example</a>.</p> | ||||
| <p>Class<strong> shared_ptr</strong> meets the <strong>CopyConstuctible</strong> | ||||
| and <strong>Assignable</strong> 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 <strong> | ||||
| shared_ptr</strong> 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.</p> | ||||
| <p>Class<strong> shared_ptr</strong> cannot correctly hold a pointer to a | ||||
| dynamically allocated array.  See <a href="shared_array.htm"><strong>shared_array</strong></a> | ||||
| for that usage.</p> | ||||
| <p>Class<strong> shared_ptr</strong> 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.</p> | ||||
| <p>The class is a template parameterized on <tt>T</tt>, the type of the object | ||||
| pointed to.   <tt>T</tt> must meet the smart pointer <a href="smart_ptr.htm#Common requirements">Common | ||||
| requirements</a>.</p> | ||||
| <h2>Class shared_ptr Synopsis</h2> | ||||
| <pre>#include <<a href="../../boost/smart_ptr.hpp">boost/smart_ptr.hpp</a>> | ||||
| namespace boost { | ||||
|  | ||||
| template<typename T> class shared_ptr { | ||||
|  | ||||
|  public: | ||||
|    typedef T <a href="#shared_ptr_element_type">element_type</a>; | ||||
|  | ||||
|    explicit <a href="#shared_ptr_ctor">shared_ptr</a>( T* p=0 ); | ||||
|   <strong> </strong><a href="#shared_ptr_~shared_ptr">~shared_ptr</a>(); | ||||
|  | ||||
|    <a href="#shared_ptr_ctor">shared_ptr</a>( const shared_ptr& );    | ||||
|    template<typename Y> | ||||
|       <a href="#shared_ptr_ctor">shared_ptr</a>(const shared_ptr<Y>& r);  // never throws | ||||
|    template<typename Y> | ||||
|       <a href="#shared_ptr_ctor">shared_ptr</a>(std::auto_ptr<Y>& r); | ||||
|  | ||||
|    shared_ptr& <a href="#shared_ptr_operator=">operator=</a>( const shared_ptr& );  // never throws   | ||||
|    template<typename Y> | ||||
|       shared_ptr& <a href="#shared_ptr_operator=">operator=</a>(const shared_ptr<Y>& r);  // never throws | ||||
|    template<typename Y> | ||||
|       shared_ptr& <a href="#shared_ptr_operator=">operator=</a>(std::auto_ptr<Y>& r); | ||||
|  | ||||
|    void <a href="#shared_ptr_reset">reset</a>( T* p=0 ); | ||||
|  | ||||
|    T& <a href="#shared_ptr_operator*">operator*</a>() const;  // never throws | ||||
|    T* <a href="#shared_ptr_operator->">operator-></a>() const;  // never throws | ||||
|    T* <a href="#shared_ptr_get">get</a>() const;  // never throws | ||||
|  | ||||
|    long <a href="#shared_ptr_use_count">use_count</a>() const;  // never throws | ||||
|    bool <a href="#shared_ptr_unique">unique</a>() const;  // never throws | ||||
|  | ||||
|    void <a href="#shared_ptr_swap">swap</a>( 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(); } | ||||
| }</pre> | ||||
| <pre>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 </pre> | ||||
| <p>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.<br> | ||||
| <br> | ||||
| Specialization of std::less allows use of shared pointers as keys in C++ | ||||
| Standard Library associative collections.<br> | ||||
| <br> | ||||
| 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).<br> | ||||
| <br> | ||||
| It's still a controversial question whether supplying only std::less is better | ||||
| than supplying a full range of comparison operators (<, >, <=, >=).</p> | ||||
| <p>The current implementation does not supply the specializations if the macro | ||||
| name BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION is defined.</p> | ||||
| <p>The current implementation does not supply the member template functions if | ||||
| the macro name BOOST_NO_MEMBER_TEMPLATES is defined.</p> | ||||
| <h2>Class shared_ptr Members</h2> | ||||
| <h3>shared_ptr <a name="shared_ptr_element_type">element_type</a></h3> | ||||
| <pre>typedef T element_type;</pre> | ||||
| <p>Provides the type of the stored pointer.</p> | ||||
| <h3><a name="shared_ptr_ctor">shared_ptr constructors</a></h3> | ||||
| <pre>explicit shared_ptr( T* p=0 );</pre> | ||||
| <p>Constructs a <strong>shared_ptr</strong>, storing a copy of <tt>p</tt>, which | ||||
| must have been allocated via a C++ <tt>new</tt> expression or be 0. Afterwards, <strong>use_count()</strong> | ||||
| is 1 (even if p==0; see <a href="#shared_ptr_~shared_ptr">~shared_ptr</a>).</p> | ||||
| <p>The only exception which may be thrown by this constructor is <tt>std::bad_alloc</tt>.   | ||||
| If an exception is thrown,  <tt>delete p</tt> is called.</p> | ||||
| <pre>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);</pre> | ||||
| <p>Constructs a <strong>shared_ptr</strong>, as if by storing a copy of the | ||||
| pointer stored in <strong>r</strong>. Afterwards, <strong>use_count()</strong> | ||||
| for all copies is 1 more than the initial <strong>r.use_count()</strong>, or 1 | ||||
| in the <strong>auto_ptr</strong> case. In the <strong>auto_ptr</strong> case, <strong>r.release()</strong> | ||||
| is called.</p> | ||||
| <p>The only exception which may be thrown by the constructor from <strong>auto_ptr</strong> | ||||
| is <tt>std::bad_alloc</tt>.   If an exception is thrown, that | ||||
| constructor has no effect.</p> | ||||
| <h3><a name="shared_ptr_~shared_ptr">shared_ptr destructor</a></h3> | ||||
| <pre>~shared_ptr();</pre> | ||||
| <p>If <strong>use_count()</strong> == 1, deletes the object pointed to by the | ||||
| stored pointer. Otherwise, <strong>use_count()</strong> for any remaining | ||||
| copies is decremented by 1. Note that in C++  <tt>delete</tt> on a pointer | ||||
| with a value of 0 is harmless.</p> | ||||
| <p>Does not throw exceptions.</p> | ||||
| <h3>shared_ptr <a name="shared_ptr_operator=">operator=</a></h3> | ||||
| <pre>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);</pre> | ||||
| <p>First, if <strong>use_count()</strong> == 1, deletes the object pointed to by | ||||
| the stored pointer. Otherwise, <strong>use_count()</strong> for any | ||||
| remaining copies is decremented by 1. Note that in C++  <tt>delete</tt> on | ||||
| a pointer with a value of 0 is harmless.</p> | ||||
| <p>Then replaces the contents of <strong>this</strong>, as if by storing a copy | ||||
| of the pointer stored in <strong>r</strong>. Afterwards, <strong>use_count()</strong> | ||||
| for all copies is 1 more than the initial <strong>r.use_count()</strong>, or 1 | ||||
| in the <strong>auto_ptr</strong> case. In the <strong>auto_ptr</strong> case, <strong>r.release()</strong> | ||||
| is called.</p> | ||||
| <p>The first two forms of <tt>operator=</tt> above do not throw exceptions.</p> | ||||
| <p>The only exception which may be thrown by the <strong>auto_ptr</strong> form | ||||
| is <tt>std::bad_alloc</tt>.   If an exception is thrown, the function | ||||
| has no effect.</p> | ||||
| <h3>shared_ptr <a name="shared_ptr_reset">reset</a></h3> | ||||
| <pre>void reset( T* p=0 );</pre> | ||||
| <p>First, if <strong>use_count()</strong> == 1, deletes the object pointed to by | ||||
| the stored pointer. Otherwise, <strong>use_count()</strong> for any | ||||
| remaining copies is decremented by 1. </p> | ||||
| <p>Then replaces the contents of <strong>this</strong>, as if by storing a copy | ||||
| of <strong>p</strong>, which must have been allocated via a C++ <tt>new</tt> | ||||
| expression or be 0. Afterwards, <strong>use_count()</strong> is 1 (even if p==0; | ||||
| see <a href="#shared_ptr_~shared_ptr">~shared_ptr</a>). Note that in C++  <tt>delete</tt> | ||||
| on a pointer with a value of 0 is harmless.</p> | ||||
| <p>The only exception which may be thrown is <tt>std::bad_alloc</tt>.  If | ||||
| an exception is thrown,  <tt>delete p</tt> is called.</p> | ||||
| <h3>shared_ptr <a name="shared_ptr_operator*">operator*</a></h3> | ||||
| <pre>T& operator*() const;  // never throws</pre> | ||||
| <p>Returns a reference to the object pointed to by the stored pointer.</p> | ||||
| <h3>shared_ptr <a name="shared_ptr_operator->">operator-></a> and <a name="shared_ptr_get">get</a></h3> | ||||
| <pre>T* operator->() const;  // never throws | ||||
| T* get() const;  // never throws</pre> | ||||
| <p><b>T</b> is not required by get() to be a complete type .  See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p> | ||||
| <p>Both return the stored pointer.</p> | ||||
| <h3>shared_ptr<a name="shared_ptr_use_count"> use_count</a></h3> | ||||
| <p><tt>long use_count() const; // never throws</tt></p> | ||||
| <p><b>T</b> is not required be a complete type.  | ||||
| See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p> | ||||
| <p>Returns the number of <strong>shared_ptrs</strong> sharing ownership of the | ||||
| stored pointer.</p> | ||||
| <h3>shared_ptr <a name="shared_ptr_unique">unique</a></h3> | ||||
| <p><tt>bool unique() const; // never throws</tt></p> | ||||
| <p><b>T</b> is not required be a complete type.  | ||||
| See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p> | ||||
| <p>Returns <strong>use_count()</strong> == 1.</p> | ||||
| <h3><a name="shared_ptr_swap">shared_ptr swap</a></h3> | ||||
| <p><code>void swap( shared_ptr<T>& other ) throw()</code></p> | ||||
| <p><b>T</b> is not required be a complete type.  | ||||
| See <a href="smart_ptr.htm#Common requirements">Common Requirements</a>.</p> | ||||
| <p>Swaps the two smart pointers, as if by std::swap.</p> | ||||
| <h2>Class <a name="shared_ptr_example">shared_ptr example</a></h2> | ||||
| <p>See <a href="shared_ptr_example.cpp"> shared_ptr_example.cpp</a> for a complete example program.</p> | ||||
| <p>This program builds a std::vector and std::set of FooPtr's.</p> | ||||
| <p>Note that after the two containers have been populated, some of the FooPtr objects | ||||
| will have use_count()==1 rather than use_count()==2, since foo_set is a std::set | ||||
| rather than a std::multiset, and thus does not contain duplicate entries.  Furthermore, use_count() may be even higher | ||||
| at various times while push_back() and insert() container operations are performed.  | ||||
| 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.</p> | ||||
| <h2><a name="Handle/Body">Handle/Body</a> Idiom</h2> | ||||
| <p>One common usage of <b>shared_ptr</b> is to implement a handle/body (also | ||||
| called pimpl) idiom which avoids exposing the body (implementation) in the header | ||||
| file.</p> | ||||
| <p>The <a href="shared_ptr_example2_test.cpp">shared_ptr_example2_test.cpp</a> | ||||
| sample program includes a header file, <a href="shared_ptr_example2.hpp">shared_ptr_example2.hpp</a>, | ||||
| which uses a <b>shared_ptr<></b> to an incomplete type to hide the | ||||
| implementation.   The | ||||
| instantiation of member functions which require a complete type occurs in the <a href="shared_ptr_example2.cpp">shared_ptr_example2.cpp</a> | ||||
| implementation file.</p> | ||||
| <h2>FAQ</h2> | ||||
| <p><b>Q</b>. Why doesn't <b>shared_ptr</b> have template parameters supplying | ||||
| traits or policies to allow extensive user customization?<br> | ||||
| <b>A</b>. Parameterization discourages users.  <b>Shared_ptr</b> 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, <b>shared_ptr</b> is the | ||||
| smart pointer of choice for a wide range of applications.</p> | ||||
| <p><b>Q</b>. Why don't <b>shared_ptr</b> (and the other Boost smart pointers) | ||||
| supply an automatic conversion to <b>T*</b>?<br> | ||||
| <b>A</b>. Automatic conversion is believed to be too error prone.</p> | ||||
| <hr> | ||||
| <p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->24 May, 2001<!--webbot bot="Timestamp" endspan i-checksum="13964" --> | ||||
| </p> | ||||
| <p><EFBFBD> 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.</p> | ||||
|  | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
							
								
								
									
										96
									
								
								shared_ptr_example.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								shared_ptr_example.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <vector> | ||||
| #include <set> | ||||
| #include <iostream> | ||||
| #include <algorithm> | ||||
| #include <boost/smart_ptr.hpp> | ||||
|  | ||||
| //  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<Foo> 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<FooPtr>         foo_vector; | ||||
|   std::set<FooPtr,FooPtrOps>  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; | ||||
| } | ||||
|  | ||||
							
								
								
									
										21
									
								
								shared_ptr_example2.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								shared_ptr_example2.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| // Boost shared_ptr_example2 implementation file  -----------------------------// | ||||
|  | ||||
| #include "shared_ptr_example2.hpp" | ||||
| #include <iostream> | ||||
|  | ||||
| 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() {} | ||||
							
								
								
									
										27
									
								
								shared_ptr_example2.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								shared_ptr_example2.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| //  Boost shared_ptr_example2 header file  -----------------------------------// | ||||
|  | ||||
| #include <boost/smart_ptr.hpp> | ||||
|  | ||||
| //  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 | ||||
| }; | ||||
|  | ||||
							
								
								
									
										15
									
								
								shared_ptr_example2_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								shared_ptr_example2_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
| } | ||||
							
								
								
									
										155
									
								
								smart_ptr.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								smart_ptr.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
| <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
| <title>Smart Pointer Classes</title> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
|  | ||||
| <h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Smart | ||||
| Pointers</h1> | ||||
| <p>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.</p> | ||||
| <p>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.</p> | ||||
| <p>The header <a href="../../boost/smart_ptr.hpp">boost/smart_ptr.hpp</a> | ||||
| provides four smart pointer template classes:</p> | ||||
| <div align="left"> | ||||
|   <table border="1" cellpadding="4" cellspacing="4"> | ||||
|     <tr> | ||||
|       <td> | ||||
|         <p align="left"><a href="scoped_ptr.htm"><strong>scoped_ptr</strong></a></td> | ||||
|       <td>Simple sole ownership of single objects. Noncopyable.</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|       <td><a href="scoped_array.htm"><strong>scoped_array</strong></a></td> | ||||
|       <td>Simple sole ownership of arrays. Noncopyable.</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|       <td><a href="shared_ptr.htm"><strong>shared_ptr</strong></a></td> | ||||
|       <td>Object ownership shared among multiple pointers</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|       <td><a href="shared_array.htm"><strong>shared_array</strong></a></td> | ||||
|       <td>Array ownership shared among multiple pointers.</td> | ||||
|     </tr> | ||||
|   </table> | ||||
| </div> | ||||
| <p>These classes are designed to complement the C++ Standard Library <tt>auto_ptr</tt> | ||||
| class.</p> | ||||
| <p>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.</p> | ||||
| <p>A test program (<a href="smart_ptr_test.cpp">smart_ptr_test.cpp</a>) is | ||||
| provided to verify correct operation.</p> | ||||
| <p>A page on <a href="smarttests.htm">Smart Pointer Timings</a> will be of | ||||
| interest to those curious about performance issues.</p> | ||||
| <h2><a name="Common requirements">Common requirements</a></h2> | ||||
| <p>These smart pointer classes have a template parameter, <tt><b>T</b></tt>, 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 <tt><b>T</b></tt>  throw exceptions.</p> | ||||
| <p><code><b>T</b></code> may be an incomplete type at the point of smart pointer | ||||
| declaration.  Unless otherwise specified, it is required that <code><b>T</b></code> | ||||
| 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 <a href="../utility/utility.htm#checked_delete">checked_delete()</a>.</p> | ||||
| <h3>Rationale</h3> | ||||
| <p>The requirements on <tt><b>T</b></tt> 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 <tt><b>T</b></tt> is an | ||||
| incomplete type.  This separates interface from implementation and hides | ||||
| implementation from translation units which merely use the interface.  | ||||
| Examples described in the documentation for specific smart pointers illustrate | ||||
| use of smart pointers in these idioms.</p> | ||||
| <h2>Exception safety</h2> | ||||
| <p>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 <tt>T</tt> meets the <a href="#Common requirements">Common | ||||
| requirements</a>)  is <tt>std::bad_alloc</tt>, and that is thrown only by | ||||
| functions which are explicitly documented as possibly throwing <tt>std::bad_alloc</tt>.</p> | ||||
| <h2>Exception-specifications</h2> | ||||
| <p>Exception-specifications are not used; see <a href="../../more/lib_guide.htm#Exception-specification">exception-specification | ||||
| rationale</a>.</p> | ||||
| <p>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: <kbd>// | ||||
| never throws</kbd>. </p> | ||||
| <p>Functions which destroy objects of the pointed to type are prohibited from | ||||
| throwing exceptions by the <a href="#Common requirements">Common requirements</a>.</p> | ||||
| <h2>History and acknowledgements</h2> | ||||
| <p>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.</p> | ||||
| <p>November, 1999. Darin Adler provided operator ==, operator !=, and std::swap | ||||
| and std::less specializations for shared types.</p> | ||||
| <p>September, 1999. Luis Coelho provided shared_ptr::swap and shared_array::swap</p> | ||||
| <p>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 <a href="../../boost/smart_ptr.hpp"><tt>smart_ptr.hpp</tt></a> | ||||
| for the specific changes made as a result of their constructive criticism.</p> | ||||
| <p>Oct, 1998.  In 1994 Greg Colvin proposed to the C++ Standards Committee | ||||
| classes named <strong>auto_ptr</strong> and <strong>counted_ptr</strong> which | ||||
| were very similar to what we now call <strong>scoped_ptr</strong> and <strong>shared_ptr</strong>.  | ||||
| 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, <strong>counted_ptr</strong> was rejected | ||||
| and surprising transfer-of-ownership semantics were added to <strong>auto-ptr</strong>.</p> | ||||
| <p>Beman Dawes proposed reviving the original semantics under the names <strong>safe_ptr</strong> | ||||
| and <strong>counted_ptr</strong> at an October, 1998, meeting of Per Andersson, | ||||
| Matt Austern, Greg Colvin, Sean Corfield, Pete Becker, Nico Josuttis, Dietmar | ||||
| K<EFBFBD>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 <strong>std::auto_ptr</strong> interface, and various | ||||
| function signatures and semantics were finalized.</p> | ||||
| <p>Over the next three months, several implementations were considered for <strong>shared_ptr</strong>, | ||||
| and discussed on the <a href="http://www.boost.org">boost.org</a> 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: | ||||
| <ul> | ||||
|   <li>Direct detached: the shared_ptr contains a pointer to the object, and a | ||||
|     pointer to the count.</li> | ||||
|   <li>Indirect detached: the shared_ptr contains a pointer to a helper object, | ||||
|     which in turn contains a pointer to the object and the count.</li> | ||||
|   <li>Embedded attached: the count is a member of the object pointed to.</li> | ||||
|   <li>Placement attached: the count is attached via operator new manipulations.</li> | ||||
| </ul> | ||||
| <p>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.</p> | ||||
| <p>But Greg Colvin and Jerry Schwarz argued that "parameterization will | ||||
| discourage users", and in the end we choose to supply only the direct | ||||
| implementation.</p> | ||||
| <p>See the Revision History section of the header for further contributors.</p> | ||||
| <hr> | ||||
| <p>Revised  <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan | ||||
| -->24 May 2001<!--webbot bot="Timestamp" endspan i-checksum="15110" | ||||
| --></p> | ||||
| <p><EFBFBD> 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.</p> | ||||
|  | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
							
								
								
									
										289
									
								
								smart_ptr_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								smart_ptr_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,289 @@ | ||||
| //  smart pointer test program  ----------------------------------------------// | ||||
|  | ||||
| //  (C) Copyright Beman Dawes 1998, 1999. Permission to copy, use, modify, sell | ||||
| //  and distribute this software is granted provided this copyright notice | ||||
| //  appears in all copies. This software is provided "as is" without express or | ||||
| //  implied warranty, and with no claim as to its suitability for any purpose. | ||||
|  | ||||
| //  Revision History | ||||
| //  24 May 01  use Boost test library for error detection, reporting, add tests | ||||
| //             for operations on incomplete types (Beman Dawes)  | ||||
| //  29 Nov 99  added std::swap and associative container tests (Darin Adler) | ||||
| //  25 Sep 99  added swap tests | ||||
| //  20 Jul 99  header name changed to .hpp | ||||
| //  20 Apr 99  additional error tests added. | ||||
|  | ||||
| #define BOOST_INCLUDE_MAIN | ||||
| #include <boost/test/test_tools.hpp> | ||||
| #include <boost/smart_ptr.hpp> | ||||
| #include <cstring> | ||||
| #include <iostream> | ||||
| #include <set> | ||||
|  | ||||
| class Incomplete; | ||||
|  | ||||
| Incomplete * get_ptr(  boost::shared_ptr<Incomplete>& incomplete ) | ||||
| { | ||||
|   return incomplete.get(); | ||||
| } | ||||
|  | ||||
| using namespace std; | ||||
| using boost::scoped_ptr; | ||||
| using boost::scoped_array; | ||||
| using boost::shared_ptr; | ||||
| using boost::shared_array; | ||||
|  | ||||
| template<typename T> | ||||
| void ck( const T* v1, T v2 ) { BOOST_TEST( *v1 == v2 ); } | ||||
|  | ||||
| namespace { | ||||
|   int UDT_use_count;  // independent of pointer maintained counts | ||||
|   } | ||||
|  | ||||
| //  user defined type  -------------------------------------------------------// | ||||
|  | ||||
| class UDT { | ||||
|   long value_; | ||||
|  public: | ||||
|   explicit UDT( long value=0 ) : value_(value) { ++UDT_use_count; } | ||||
|   ~UDT() { | ||||
|     --UDT_use_count; | ||||
|     cout << "UDT with value " << value_ << " being destroyed" << endl; | ||||
|     } | ||||
|   long value() const { return value_; } | ||||
|   void value( long v ) { value_ = v;; } | ||||
|   };  // UDT | ||||
|  | ||||
| //  tests on incomplete types  -----------------------------------------------// | ||||
|  | ||||
| //  Certain smart pointer operations are specified to work on incomplete types, | ||||
| //  and some uses depend upon this feature.  These tests verify compilation | ||||
| //  only - the functions aren't actually invoked. | ||||
|  | ||||
| class Incomplete; | ||||
|  | ||||
| Incomplete * check_incomplete( scoped_ptr<Incomplete>& incomplete ) | ||||
| { | ||||
|   return incomplete.get(); | ||||
| } | ||||
|  | ||||
| Incomplete * check_incomplete( shared_ptr<Incomplete>& incomplete, | ||||
|                                shared_ptr<Incomplete>& i2 ) | ||||
| { | ||||
|   incomplete.swap(i2); | ||||
|   cout << incomplete.use_count() << " " << incomplete.unique() << endl; | ||||
|   return incomplete.get(); | ||||
| } | ||||
| //  main  --------------------------------------------------------------------// | ||||
|  | ||||
| //  This isn't a very systematic test; it just hits some of the basics. | ||||
|  | ||||
| int test_main( int, char ** ) { | ||||
|  | ||||
|   BOOST_TEST( UDT_use_count == 0 );  // reality check | ||||
|  | ||||
|   //  test scoped_ptr with a built-in type | ||||
|   long * lp = new long; | ||||
|   scoped_ptr<long> sp ( lp ); | ||||
|   BOOST_TEST( sp.get() == lp ); | ||||
|   BOOST_TEST( lp == sp.get() ); | ||||
|   BOOST_TEST( &*sp == lp ); | ||||
|  | ||||
|   *sp = 1234568901L; | ||||
|   BOOST_TEST( *sp == 1234568901L ); | ||||
|   BOOST_TEST( *lp == 1234568901L ); | ||||
|   ck( static_cast<long*>(sp.get()), 1234568901L ); | ||||
|   ck( lp, *sp ); | ||||
|  | ||||
|   sp.reset(); | ||||
|   BOOST_TEST( sp.get() == 0 ); | ||||
|  | ||||
|   //  test scoped_ptr with a user defined type | ||||
|   scoped_ptr<UDT> udt_sp ( new UDT( 999888777 ) ); | ||||
|   BOOST_TEST( udt_sp->value() == 999888777 ); | ||||
|   udt_sp.reset(); | ||||
|   udt_sp.reset( new UDT( 111222333 ) ); | ||||
|   BOOST_TEST( udt_sp->value() == 111222333 ); | ||||
|   udt_sp.reset( new UDT( 333222111 ) ); | ||||
|   BOOST_TEST( udt_sp->value() == 333222111 ); | ||||
|  | ||||
|   //  test scoped_array with a build-in type | ||||
|   char * sap = new char [ 100 ]; | ||||
|   scoped_array<char> sa ( sap ); | ||||
|   BOOST_TEST( sa.get() == sap ); | ||||
|   BOOST_TEST( sap == sa.get() ); | ||||
|  | ||||
|   strcpy( sa.get(), "Hot Dog with mustard and relish" ); | ||||
|   BOOST_TEST( strcmp( sa.get(), "Hot Dog with mustard and relish" ) == 0 ); | ||||
|   BOOST_TEST( strcmp( sap, "Hot Dog with mustard and relish" ) == 0 ); | ||||
|  | ||||
|   BOOST_TEST( sa[0] == 'H' ); | ||||
|   BOOST_TEST( sa[30] == 'h' ); | ||||
|  | ||||
|   sa[0] = 'N'; | ||||
|   sa[4] = 'd'; | ||||
|   BOOST_TEST( strcmp( sap, "Not dog with mustard and relish" ) == 0 ); | ||||
|  | ||||
|   sa.reset(); | ||||
|   BOOST_TEST( sa.get() == 0 ); | ||||
|  | ||||
|   //  test shared_ptr with a built-in type | ||||
|   int * ip = new int; | ||||
|   shared_ptr<int> cp ( ip ); | ||||
|   BOOST_TEST( ip == cp.get() ); | ||||
|   BOOST_TEST( cp.use_count() == 1 ); | ||||
|  | ||||
|   *cp = 54321; | ||||
|   BOOST_TEST( *cp == 54321 ); | ||||
|   BOOST_TEST( *ip == 54321 ); | ||||
|   ck( static_cast<int*>(cp.get()), 54321 ); | ||||
|   ck( static_cast<int*>(ip), *cp ); | ||||
|  | ||||
|   shared_ptr<int> cp2 ( cp ); | ||||
|   BOOST_TEST( ip == cp2.get() ); | ||||
|   BOOST_TEST( cp.use_count() == 2 ); | ||||
|   BOOST_TEST( cp2.use_count() == 2 ); | ||||
|  | ||||
|   BOOST_TEST( *cp == 54321 ); | ||||
|   BOOST_TEST( *cp2 == 54321 ); | ||||
|   ck( static_cast<int*>(cp2.get()), 54321 ); | ||||
|   ck( static_cast<int*>(ip), *cp2 ); | ||||
|    | ||||
|   shared_ptr<int> cp3 ( cp ); | ||||
|   BOOST_TEST( cp.use_count() == 3 ); | ||||
|   BOOST_TEST( cp2.use_count() == 3 ); | ||||
|   BOOST_TEST( cp3.use_count() == 3 ); | ||||
|   cp.reset(); | ||||
|   BOOST_TEST( cp2.use_count() == 2 ); | ||||
|   BOOST_TEST( cp3.use_count() == 2 ); | ||||
|   BOOST_TEST( cp.use_count() == 1 ); | ||||
|   cp.reset( new int ); | ||||
|   *cp =  98765; | ||||
|   BOOST_TEST( *cp == 98765 ); | ||||
|   *cp3 = 87654; | ||||
|   BOOST_TEST( *cp3 == 87654 ); | ||||
|   BOOST_TEST( *cp2 == 87654 ); | ||||
|   cp.swap( cp3 ); | ||||
|   BOOST_TEST( *cp == 87654 ); | ||||
|   BOOST_TEST( *cp2 == 87654 ); | ||||
|   BOOST_TEST( *cp3 == 98765 ); | ||||
|   cp.swap( cp3 ); | ||||
|   BOOST_TEST( *cp == 98765 ); | ||||
|   BOOST_TEST( *cp2 == 87654 ); | ||||
|   BOOST_TEST( *cp3 == 87654 ); | ||||
|   cp2 = cp2; | ||||
|   BOOST_TEST( cp2.use_count() == 2 ); | ||||
|   BOOST_TEST( *cp2 == 87654 ); | ||||
|   cp = cp2; | ||||
|   BOOST_TEST( cp2.use_count() == 3 ); | ||||
|   BOOST_TEST( *cp2 == 87654 ); | ||||
|   BOOST_TEST( cp.use_count() == 3 ); | ||||
|   BOOST_TEST( *cp == 87654 ); | ||||
|    | ||||
|   shared_ptr<int> cp4; | ||||
|   swap( cp2, cp4 ); | ||||
|   BOOST_TEST( cp4.use_count() == 3 ); | ||||
|   BOOST_TEST( *cp4 == 87654 ); | ||||
|   BOOST_TEST( cp2.get() == 0 ); | ||||
|    | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|   set< shared_ptr<int> > scp; | ||||
|   scp.insert(cp4); | ||||
|   BOOST_TEST( scp.find(cp4) != scp.end() ); | ||||
|   BOOST_TEST( scp.find(cp4) == scp.find( shared_ptr<int>(cp4) ) ); | ||||
| #endif | ||||
|  | ||||
|   //  test shared_array with a built-in type | ||||
|   char * cap = new char [ 100 ]; | ||||
|   shared_array<char> ca ( cap ); | ||||
|   BOOST_TEST( ca.get() == cap ); | ||||
|   BOOST_TEST( cap == ca.get() ); | ||||
|   BOOST_TEST( &ca[0] == cap ); | ||||
|  | ||||
|   strcpy( ca.get(), "Hot Dog with mustard and relish" ); | ||||
|   BOOST_TEST( strcmp( ca.get(), "Hot Dog with mustard and relish" ) == 0 ); | ||||
|   BOOST_TEST( strcmp( cap, "Hot Dog with mustard and relish" ) == 0 ); | ||||
|  | ||||
|   BOOST_TEST( ca[0] == 'H' ); | ||||
|   BOOST_TEST( ca[30] == 'h' ); | ||||
|    | ||||
|   shared_array<char> ca2 ( ca ); | ||||
|   shared_array<char> ca3 ( ca2 ); | ||||
|  | ||||
|   ca[0] = 'N'; | ||||
|   ca[4] = 'd'; | ||||
|   BOOST_TEST( strcmp( ca.get(), "Not dog with mustard and relish" ) == 0 ); | ||||
|   BOOST_TEST( strcmp( ca2.get(), "Not dog with mustard and relish" ) == 0 ); | ||||
|   BOOST_TEST( strcmp( ca3.get(), "Not dog with mustard and relish" ) == 0 ); | ||||
|   BOOST_TEST( ca.use_count() == 3 ); | ||||
|   BOOST_TEST( ca2.use_count() == 3 ); | ||||
|   BOOST_TEST( ca3.use_count() == 3 ); | ||||
|   ca2.reset(); | ||||
|   BOOST_TEST( ca.use_count() == 2 ); | ||||
|   BOOST_TEST( ca3.use_count() == 2 ); | ||||
|   BOOST_TEST( ca2.use_count() == 1 ); | ||||
|  | ||||
|   ca.reset(); | ||||
|   BOOST_TEST( ca.get() == 0 ); | ||||
|  | ||||
|   shared_array<char> ca4; | ||||
|   swap( ca3, ca4 ); | ||||
|   BOOST_TEST( ca4.use_count() == 1 ); | ||||
|   BOOST_TEST( strcmp( ca4.get(), "Not dog with mustard and relish" ) == 0 ); | ||||
|   BOOST_TEST( ca3.get() == 0 ); | ||||
|    | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|   set< shared_array<char> > sca; | ||||
|   sca.insert(ca4); | ||||
|   BOOST_TEST( sca.find(ca4) != sca.end() ); | ||||
|   BOOST_TEST( sca.find(ca4) == sca.find( shared_array<char>(ca4) ) ); | ||||
| #endif | ||||
|  | ||||
|   //  test shared_array with user defined type | ||||
|   shared_array<UDT> udta ( new UDT[3] ); | ||||
|  | ||||
|   udta[0].value( 111 ); | ||||
|   udta[1].value( 222 ); | ||||
|   udta[2].value( 333 ); | ||||
|   shared_array<UDT> udta2 ( udta ); | ||||
|  | ||||
|   BOOST_TEST( udta[0].value() == 111 ); | ||||
|   BOOST_TEST( udta[1].value() == 222 ); | ||||
|   BOOST_TEST( udta[2].value() == 333 ); | ||||
|   BOOST_TEST( udta2[0].value() == 111 ); | ||||
|   BOOST_TEST( udta2[1].value() == 222 ); | ||||
|   BOOST_TEST( udta2[2].value() == 333 ); | ||||
|   udta2.reset(); | ||||
|   BOOST_TEST( udta2.get() == 0 ); | ||||
|   BOOST_TEST( udta.use_count() == 1 ); | ||||
|   BOOST_TEST( udta2.use_count() == 1 ); | ||||
|  | ||||
|   BOOST_TEST( UDT_use_count == 4 );  // reality check | ||||
|  | ||||
|   //  test shared_ptr with a user defined type | ||||
|   UDT * up = new UDT; | ||||
|   shared_ptr<UDT> sup ( up ); | ||||
|   BOOST_TEST( up == sup.get() ); | ||||
|   BOOST_TEST( sup.use_count() == 1 ); | ||||
|  | ||||
|   sup->value( 54321 ) ; | ||||
|   BOOST_TEST( sup->value() == 54321 ); | ||||
|   BOOST_TEST( up->value() == 54321 ); | ||||
|  | ||||
|   shared_ptr<UDT> sup2; | ||||
|   sup2 = sup; | ||||
|   BOOST_TEST( sup2->value() == 54321 ); | ||||
|   BOOST_TEST( sup.use_count() == 2 ); | ||||
|   BOOST_TEST( sup2.use_count() == 2 ); | ||||
|   sup2 = sup2; | ||||
|   BOOST_TEST( sup2->value() == 54321 ); | ||||
|   BOOST_TEST( sup.use_count() == 2 ); | ||||
|   BOOST_TEST( sup2.use_count() == 2 ); | ||||
|  | ||||
|   cout << "OK" << endl; | ||||
|  | ||||
|   new char[12345]; // deliberate memory leak to verify leaks detected | ||||
|  | ||||
|   return 0; | ||||
|   } // main | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								smarttest.zip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								smarttest.zip
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										540
									
								
								smarttests.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										540
									
								
								smarttests.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,540 @@ | ||||
| <html> | ||||
| <head> | ||||
| <title>boost: smart pointer tests</title> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> | ||||
| <!-- | ||||
| --> | ||||
| <body bgcolor="#FFFFFF"> | ||||
|  | ||||
| <h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" WIDTH="277" HEIGHT="86">Smart | ||||
| Pointers Timings </h1> | ||||
|  | ||||
| <p>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.</p> | ||||
| <p>Thanks are due to <a href="../../people/dave_abrahams.htm"> Dave Abrahams</a>, | ||||
| <a href="../../people/gavin_collings.htm"> Gavin Collings</a>, <a href="../../people/greg_colvin.htm"> Greg Colvin</a> and | ||||
| <a href="../../people/beman_dawes.html"> Beman Dawes</a>  | ||||
|   for test code and trial implementations, the final version of which can be found  | ||||
|   in .zip format <a href="smarttest.zip">here</a>.</p> | ||||
| <h2>Description</h2> | ||||
| <p>Two tests were run: the first aimed to obtain timings for two basic individual  | ||||
|   operations:</p> | ||||
| <ol type="i"> | ||||
|   <li> Initial construction from raw pointer.</li> | ||||
|   <li> An amortized copy operation consisting of half an assignment and half a  | ||||
|     copy construction - designed to reflect average usage.</li> | ||||
| </ol> | ||||
| <p>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.</p> | ||||
| <p>Five smart pointer implementation strategies were tested:</p> | ||||
| <ol type="i"> | ||||
|   <li>Counted pointer using a heap allocated reference count, this is referred  | ||||
|     to as <b>simple counted</b>.</li> | ||||
|   <li>Counted pointer using a special purpose allocator for the reference count  | ||||
|     - <b>special counted</b>.</li> | ||||
|   <li>Counted pointer using an intrusive reference count - <b>intrusive</b>.</li> | ||||
|   <li>Linked pointer as described above - <b>linked</b>.</li> | ||||
|   <li>Cyclic pointer, a counted implementation using a std::deque for allocation  | ||||
|     with provision for weak pointers and garbage collection of cycles of pointers  | ||||
|     - <b>cyclic</b>.</li> | ||||
| </ol> | ||||
| <p>on two compilers:</p> | ||||
| <ol type="i"> | ||||
|   <li>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).</li> | ||||
|   <li>gcc 2.95.2 using full optimization (-O3 -DNDEBUG).</li> | ||||
| </ol> | ||||
| <p>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.</p> | ||||
| <p>All tests were run on a PII-200 running Windows NT version 4.0</p> | ||||
| <h2> </h2> | ||||
| <h2>Operation Timing Test Results</h2> | ||||
| <p>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.</p> | ||||
| <table border="0" align="center"> | ||||
|   <tr>  | ||||
|     <td width="20" height="20"> </td> | ||||
|     <td> </td> | ||||
|     <td width="20"> </td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <td width="20">  </td> | ||||
|     <td><img src="msvcspeed.gif" width="560" height="355"></td> | ||||
|     <td width="20"> </td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <td height="20"> </td> | ||||
|     <td> </td> | ||||
|     <td> </td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <td> </td> | ||||
|     <td><img src="gccspeed.gif" width="560" height="355"></td> | ||||
|     <td> </td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <td height="20"> </td> | ||||
|     <td> </td> | ||||
|     <td> </td> | ||||
|   </tr> | ||||
| </table> | ||||
| <p> </p> | ||||
| <p>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) : -</p> | ||||
| <p> </p> | ||||
| <h4 align="center">MSVC</h4> | ||||
| <table align="center" cellpadding="5" cellspacing="0" class="codetable" width="400"> | ||||
|   <tr>  | ||||
|     <th width="120">  | ||||
|       <div align="right"></div> | ||||
|     </th> | ||||
|     <th class="codetabletop" width="120">  | ||||
|       <div align="center">initialization</div> | ||||
|     </th> | ||||
|     <th class="codetabletop" width="120">copy operation</th> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">simple counted</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">3000 +/- 170</td> | ||||
|     <td class="codetablecell" align="center">104 +/- 31</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">special counted</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">1330 +/- 50</td> | ||||
|     <td class="codetablecell" align="center">85 +/- 9</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">intrusive</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">1000 +/- 20</td> | ||||
|     <td class="codetablecell" align="center">71 +/- 3</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft" align="right">linked</th> | ||||
|     <td class="codetablecell" align="center">970 +/- 60</td> | ||||
|     <td class="codetablecell" align="center">136 +/- 10</td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <th class="codetableleft" align="right">cyclic</th> | ||||
|     <td class="codetablecell" align="center">1290 +/- 70</td> | ||||
|     <td class="codetablecell" align="center">112 +/- 12</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft" align="right">dumb</th> | ||||
|     <td class="codetablecell" align="center">1020 +/- 20</td> | ||||
|     <td class="codetablecell" align="center">10 +/- 4</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">raw</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">1038 +/- 30</td> | ||||
|     <td class="codetablecell" align="center">10 +/- 5</td> | ||||
|   </tr> | ||||
| </table> | ||||
| <h4 align="center"> </h4> | ||||
| <h4 align="center">GCC</h4> | ||||
| <table align="center" cellpadding="5" cellspacing="0" class="codetable" width="400"> | ||||
|   <tr>  | ||||
|     <th width="120">  | ||||
|       <div align="right"></div> | ||||
|     </th> | ||||
|     <th class="codetabletop" width="120">  | ||||
|       <div align="center">initialization</div> | ||||
|     </th> | ||||
|     <th class="codetabletop" width="120">copy operation</th> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">simple counted</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">4620 +/- 150</td> | ||||
|     <td class="codetablecell" align="center">301 +/- 28</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">special counted</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">1990 +/- 40</td> | ||||
|     <td class="codetablecell" align="center">264 +/- 7</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">intrusive</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">1590 +/- 70</td> | ||||
|     <td class="codetablecell" align="center">181 +/- 12</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft" align="right">linked</th> | ||||
|     <td class="codetablecell" align="center">1470 +/- 140</td> | ||||
|     <td class="codetablecell" align="center">345 +/- 26</td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <th class="codetableleft" align="right">cyclic</th> | ||||
|     <td class="codetablecell" align="center">2180 +/- 100</td> | ||||
|     <td class="codetablecell" align="center">330 +/- 18</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft" align="right">dumb</th> | ||||
|     <td class="codetablecell" align="center">1590 +/- 70</td> | ||||
|     <td class="codetablecell" align="center">74 +/- 12</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft" align="right">  | ||||
|       <div align="right">raw</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">1430 +/- 60</td> | ||||
|     <td class="codetablecell" align="center">27 +/- 11</td> | ||||
|   </tr> | ||||
| </table> | ||||
| <p>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.</p> | ||||
| <h3>Detail</h3> | ||||
| <p>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.</p> | ||||
| <h2> </h2> | ||||
| <h2>Container Test Results</h2> | ||||
| <p>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.</p> | ||||
| <p>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.</p> | ||||
| <p> All times are in seconds for 300,000 contained pointers.</p> | ||||
| <h4 align="center">GCC</h4> | ||||
| <table align="center" cellpadding="5" cellspacing="0" class="codetable" width="500"> | ||||
|   <tr>  | ||||
|     <th> </th> | ||||
|     <th class="codetabletop" colspan="2">vector</th> | ||||
|     <th class="codetabletop" colspan="2">list</th> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th width="120">  | ||||
|       <div align="right"></div> | ||||
|     </th> | ||||
|     <th class="codetabletop2" width="80">  | ||||
|       <div align="center">fill</div> | ||||
|     </th> | ||||
|     <th class="codetabletop2" width="80">sort</th> | ||||
|     <th class="codetabletop2" width="80">fill</th> | ||||
|     <th class="codetabletop2" width="80">sort</th> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">simple counted</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">46.54</td> | ||||
|     <td class="codetablecell" align="center">2.44</td> | ||||
|     <td class="codetablecell" align="center">47.09</td> | ||||
|     <td class="codetablecell" align="center">3.22</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">special counted</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">14.02</td> | ||||
|     <td class="codetablecell" align="center">2.83</td> | ||||
|     <td class="codetablecell" align="center">7.28</td> | ||||
|     <td class="codetablecell" align="center">3.21</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">intrusive</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">12.15</td> | ||||
|     <td class="codetablecell" align="center">1.91</td> | ||||
|     <td class="codetablecell" align="center">7.99</td> | ||||
|     <td class="codetablecell" align="center">3.08</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft" align="right">linked</th> | ||||
|     <td class="codetablecell" align="center">12.46</td> | ||||
|     <td class="codetablecell" align="center">2.32</td> | ||||
|     <td class="codetablecell" align="center">8.14</td> | ||||
|     <td class="codetablecell" align="center">3.27</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft" align="right">cyclic</th> | ||||
|     <td class="codetablecell" align="center">22.60</td> | ||||
|     <td class="codetablecell" align="center">3.19</td> | ||||
|     <td class="codetablecell" align="center">1.63</td> | ||||
|     <td class="codetablecell" align="center">3.18</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft" align="right">  | ||||
|       <div align="right">raw</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">11.81</td> | ||||
|     <td class="codetablecell" align="center">0.24</td> | ||||
|     <td class="codetablecell" align="center">27.51</td> | ||||
|     <td class="codetablecell" align="center">0.77</td> | ||||
|   </tr> | ||||
| </table> | ||||
| <p> </p> | ||||
| <h4 align="center">MSVC</h4> | ||||
| <table align="center" cellpadding="5" cellspacing="0" class="codetable" width="500"> | ||||
|   <tr>  | ||||
|     <th> </th> | ||||
|     <th class="codetabletop" colspan="2">vector</th> | ||||
|     <th class="codetabletop" colspan="2">list</th> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th width="120">  | ||||
|       <div align="right"></div> | ||||
|     </th> | ||||
|     <th class="codetabletop2" width="80">  | ||||
|       <div align="center">fill</div> | ||||
|     </th> | ||||
|     <th class="codetabletop2" width="80">sort</th> | ||||
|     <th class="codetabletop2" width="80">fill</th> | ||||
|     <th class="codetabletop2" width="80">sort</th> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">simple counted</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">1.83</td> | ||||
|     <td class="codetablecell" align="center">2.37</td> | ||||
|     <td class="codetablecell" align="center">1.86</td> | ||||
|     <td class="codetablecell" align="center">4.85</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">special counted</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">1.04</td> | ||||
|     <td class="codetablecell" align="center">2.35</td> | ||||
|     <td class="codetablecell" align="center">1.38</td> | ||||
|     <td class="codetablecell" align="center">4.58</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">intrusive</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">1.04</td> | ||||
|     <td class="codetablecell" align="center">1.84</td> | ||||
|     <td class="codetablecell" align="center">1.16</td> | ||||
|     <td class="codetablecell" align="center">4.29</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft" align="right">linked</th> | ||||
|     <td class="codetablecell" align="center">1.08</td> | ||||
|     <td class="codetablecell" align="center">2.00</td> | ||||
|     <td class="codetablecell" align="center">1.21</td> | ||||
|     <td class="codetablecell" align="center">4.33</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft" align="right">cyclic</th> | ||||
|     <td class="codetablecell" align="center">1.38</td> | ||||
|     <td class="codetablecell" align="center">2.84</td> | ||||
|     <td class="codetablecell" align="center">1.47</td> | ||||
|     <td class="codetablecell" align="center">4.73</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft" align="right">  | ||||
|       <div align="right">raw</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">0.67</td> | ||||
|     <td class="codetablecell" align="center">0.28</td> | ||||
|     <td class="codetablecell" align="center">1.24</td> | ||||
|     <td class="codetablecell" align="center">1.81</td> | ||||
|   </tr> | ||||
| </table> | ||||
| <p> </p> | ||||
| <h2>Code Size</h2> | ||||
| <p>The following code sizes were determined by inspection of generated code for  | ||||
|   MSVC only. Sizes are given in the form N / M / I where:</p> | ||||
| <ul type="circle"> | ||||
|   <li> N is the instruction count of the operation</li> | ||||
|   <li>M is the size of the code in bytes</li> | ||||
|   <li>I determines whether generated code was inlined or not I = inline, O = "outline"</li> | ||||
| </ul> | ||||
| <p> </p> | ||||
| <table align="center" cellpadding="5" cellspacing="0" class="codetable" width="570"> | ||||
|   <tr>  | ||||
|     <th height="28" width="140">  | ||||
|       <div align="right"></div> | ||||
|     </th> | ||||
|     <th height="28" class="codetabletop" width="80">  | ||||
|       <div align="center">ptr()</div> | ||||
|     </th> | ||||
|     <th height="28" class="codetabletop" width="80">ptr(p)</th> | ||||
|     <th height="28" class="codetabletop" width="80">ptr(ptr)</th> | ||||
|     <th height="28" class="codetabletop" width="80">op=()</th> | ||||
|     <th height="28" class="codetabletop" width="80">  | ||||
|       <div align="center">~ptr()</div> | ||||
|     </th> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">simple counted</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center">38/110/O</td> | ||||
|     <td class="codetablecell" align="center">38/110/O</td> | ||||
|     <td class="codetablecell" align="center">9/23/I</td> | ||||
|     <td class="codetablecell" align="center">22/57/I</td> | ||||
|     <td class="codetablecell" align="center">17/40/I</td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">special counted</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center"><font size="-1">50/141/O</font></td> | ||||
|     <td class="codetablecell" align="center"><font size="-1">50/141/O</font></td> | ||||
|     <td class="codetablecell" align="center"><font size="-1">9/23/I</font></td> | ||||
|     <td class="codetablecell" align="center"><font size="-1">23/64/I</font></td> | ||||
|     <td class="codetablecell" align="center"><font size="-1">13/38/I</font></td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">intrusive</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center"><font size="-1">1/2/I</font></td> | ||||
|     <td class="codetablecell" align="center"><font size="-1">3/6/I</font></td> | ||||
|     <td class="codetablecell" align="center"><font size="-1">3/6/I</font></td> | ||||
|     <td class="codetablecell" align="center"><font size="-1">6/11/I</font></td> | ||||
|     <td class="codetablecell" align="center"><font size="-1">6/11/I</font></td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">linked</div> | ||||
|     </th> | ||||
|     <td class="codetablecell" align="center"><font size="-1">5/19/I</font></td> | ||||
|     <td class="codetablecell" align="center"><font size="-1">5/15/I</font></td> | ||||
|     <td class="codetablecell" align="center"><font size="-1">10/30/I</font></td> | ||||
|     <td class="codetablecell" align="center"><font size="-1">27/59/I</font></td> | ||||
|     <td class="codetablecell" align="center"><font size="-1">14/38/I</font></td> | ||||
|   </tr> | ||||
| </table> | ||||
| <p>During the code inspection, a couple of minor points were noticed: -</p> | ||||
| <ul> | ||||
|   <li>Function inlining was critical to performance.</li> | ||||
|   <li>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.</li> | ||||
| </ul> | ||||
| <h2> </h2> | ||||
| <h2>Data Size</h2> | ||||
| <p>The following smart pointer sizes were obtained in bytes</p> | ||||
| <table align="center" cellpadding="5" cellspacing="0" class="codetable" width="270"> | ||||
|   <tr>  | ||||
|     <th height="28" width="150">  | ||||
|       <div align="right"></div> | ||||
|     </th> | ||||
|     <th height="28" class="codetabletop" width="60">  | ||||
|       <div align="center">MSVC</div> | ||||
|     </th> | ||||
|     <th height="28" class="codetabletop" width="60">  | ||||
|       <div align="center">GCC</div> | ||||
|     </th> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">simple counted</div> | ||||
|     </th> | ||||
|     <td class="codetablecell">  | ||||
|       <div align="center">8</div> | ||||
|     </td> | ||||
|     <td class="codetablecell">  | ||||
|       <div align="center">8</div> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">special counted</div> | ||||
|     </th> | ||||
|     <td class="codetablecell">  | ||||
|       <div align="center">8</div> | ||||
|     </td> | ||||
|     <td class="codetablecell">  | ||||
|       <div align="center">12</div> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">intrusive</div> | ||||
|     </th> | ||||
|     <td class="codetablecell">  | ||||
|       <div align="center">4</div> | ||||
|     </td> | ||||
|     <td class="codetablecell">  | ||||
|       <div align="center">4</div> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">linked</div> | ||||
|     </th> | ||||
|     <td class="codetablecell">  | ||||
|       <div align="center">12</div> | ||||
|     </td> | ||||
|     <td class="codetablecell">  | ||||
|       <div align="center">12</div> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr>  | ||||
|     <th class="codetableleft">  | ||||
|       <div align="right">cyclic</div> | ||||
|     </th> | ||||
|     <td class="codetablecell">  | ||||
|       <div align="center">8</div> | ||||
|     </td> | ||||
|     <td class="codetablecell">  | ||||
|       <div align="center">8</div> | ||||
|     </td> | ||||
|   </tr> | ||||
| </table> | ||||
| <h2> </h2> | ||||
| <h2>Summary</h2> | ||||
| <p>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: -</p> | ||||
| <ul> | ||||
|   <li>Deterministic individual, as opposed to amortized, operation time. This  | ||||
|     weighs against any implementation depending on an allocator.</li> | ||||
|   <li>Multithreaded synchronization. This weighs against an implementation which  | ||||
|     spreads its information as in the case of linked pointer.</li> | ||||
| </ul> | ||||
| <hr> | ||||
| <p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %b %Y" startspan -->27 Jul 2000<!--webbot bot="Timestamp" endspan i-checksum="14992" --> | ||||
| </p> | ||||
| <p><EFBFBD> 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.</p> | ||||
| </body> | ||||
| </html> | ||||
		Reference in New Issue
	
	Block a user