From 309e6dd82eb445e5c18c0ff62a499fd24e945050 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 14 Feb 2002 17:12:07 +0000 Subject: [PATCH] Revised to match the style of the C++ standard. [SVN r12806] --- shared_ptr.htm | 731 ++++++++++++++++++++++++++----------------------- 1 file changed, 389 insertions(+), 342 deletions(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index 0cc96f1..be3b1c5 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -1,376 +1,423 @@ - + + shared_ptr + + + +

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

+

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

+

Introduction

+

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

+

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

+

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

+

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

+

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

+

Synopsis

+
namespace boost {
 
-
-
-shared_ptr
-
-
-
-
-

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

- -

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

- -

Introduction

- -

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

- -

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

- -

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

- -

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

- -

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

- -

Synopsis

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

Members

- -

element_type

-
typedef T element_type;
-

Provides the type of the stored pointer.

- -

constructors

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

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

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

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

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

Constructs a shared_ptr, as if by storing a copy of the -pointer stored in r. Afterwards, the use count -for all copies is 1 more than the initial use count, or 1 -in the auto_ptr case. In the auto_ptr case, r.release() -is called. -The only exception which may be thrown is std::bad_alloc, -which may be thrown during construction from auto_ptr. -If an exception is thrown, the constructor has no effect.

- -

destructor

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

Decrements the use count. Then, if the use count is 0, -deletes the object pointed to by the stored pointer. -Note that delete on a pointer with a value of 0 is harmless. -T need not be a complete type. -The guarantee that this does not throw exceptions depends on the requirement that the -deleted object's destructor does not throw exceptions. -See the smart pointer common requirements.

- -

assignment

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

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

- -

reset

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

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

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

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

- -

indirection

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

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

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

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

- -

get

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

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

- -

unique

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

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

- -

use_count

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

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

-

Because use_count is not necessarily efficient to implement for -implementations of shared_ptr that do not use an explicit reference -count, it might be removed from some future version. Thus it should -be used for debugging purposes only, and not production code.

- -

swap

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

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

- -

Free Functions

- -

comparison

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

Members

+

element_type

+
typedef T element_type;
+
+

Provides the type of the template parameter T.

+
+

constructors

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

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

+

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

+

Postconditions: use count is 1.

+

Throws: std::bad_alloc.

+

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

+

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

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

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

+

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

+

Postconditions: use count is 1.

+

Throws: std::bad_alloc.

+

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

+

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

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

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

+

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

+

Throws: nothing.

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

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

+

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

+

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

+

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

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

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

+

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

+

Throws: std::bad_alloc.

+

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

+
+

destructor

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

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

+

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

+

Throws: nothing.

+

Notes: T need not be a complete type. The guarantee that the + destructor does not throw exceptions depends on the requirement that the + deleted object's destructor does not throw exceptions. See the smart pointer + common requirements.

+
+

assignment

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

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

+
+

reset

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

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

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

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

+
+

indirection

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

Requirements: The stored pointer must not be 0.

+

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

+

Throws: nothing.

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

Requirements: The stored pointer must not be 0.

+

Returns: the stored pointer.

+

Throws: nothing.

+
+

get

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

Returns: the stored pointer.

+

Throws: nothing.

+

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

+
+

unique

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

Returns: use_count() == 1.

+

Throws: nothing.

+

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

+
+

use_count

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

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

+

Throws: nothing.

+

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

+
+

swap

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

Effects: Exchanges the contents of the two smart pointers.

+

Throws: nothing.

+

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

+
+

Free Functions

+

comparison

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

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

+

Throws: nothing.

+

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

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

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

+

Throws: nothing.

+

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

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

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

-

The operator< overload is provided to define an ordering so that shared_ptr -objects can be used in associative containers such as std::map. -The implementation uses std::less<T *> to perform the -comparison. This ensures that the comparison is handled correctly, since the -standard mandates that relational operations on pointers are unspecified (5.9 [expr.rel] -paragraph 2) but std::less<> on pointers is well-defined (20.3.3 [lib.comparisons] -paragraph 8).

- -

swap

-
template<typename T>
+		
+

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

+

Throws: nothing.

+

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

+
+

swap

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

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

- -

shared_static_cast

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

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

-

Note that the seemingly equivalent expression

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

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

- -

shared_dynamic_cast

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

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

-

Note that the seemingly equivalent expression

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

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

- -

shared_polymorphic_cast

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

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

- -

shared_polymorphic_downcast

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

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

- -

Example

- -

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

- -

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

- -

Handle/Body Idiom

- -

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

- -

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

- -

Frequently Asked Questions

- -

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

- -

Q. Why doesn't shared_ptr use a linked list implementation?
-A. A linked list implementation does not offer enough advantages to -offset the added cost of an extra pointer. See timings -page.

- -

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

- -

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

- -

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

- -

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

-

Consider:

-
shared_ptr<int> a(new int);
+		
+

Effects: Equivalent to a.swap(b).

+

Throws: nothing.

+

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

+
+

shared_static_cast

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

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

+

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

+

Throws: nothing.

+

Notes: the seemingly equivalent expression

+

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

+

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

+
+

shared_dynamic_cast

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

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

+

Returns:

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

Throws: std::bad_alloc.

+

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

+

Notes: the seemingly equivalent expression

+

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

+

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

+
+

shared_polymorphic_cast

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

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

+

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

+

Throws: std::bad_cast.

+

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

+
+

shared_polymorphic_downcast

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

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

+

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

+

Throws: nothing.

+
+

Example

+

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

+

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

+

Handle/Body Idiom

+

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

+

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

+

Frequently Asked Questions

+

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

+

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

+

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

+

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

+

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

+

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

+

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

+

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

+

Consider:

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

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

- -
- -

Revised 8 February 2002

- -

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

- - - +// Who owns p now? b will still call delete on it in its destructor.
+
+

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

+
+

Revised  + 14 February 2002

+

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

+