Class shared_ptr stores a pointer to a dynamically allocated object. (Dynamically allocated objects are allocated with the C++ new expression.) The object pointed to is guaranteed to be deleted when the last shared_ptr pointing to it is deleted or reset. See example.
Class shared_ptr meets the CopyConstuctible and Assignable requirements of the C++ Standard Library, and so can be used in C++ Standard Library containers. A specialization of std:: less< > for boost::shared_ptr<Y> is supplied so that shared_ptr works by default for Standard Library's Associative Container Compare template parameter. For compilers not supporting partial specialization, the user must explicitly pass the less<> functor.
Class shared_ptr cannot correctly hold a pointer to a dynamically allocated array. See shared_array for that usage.
Class shared_ptr will not work correctly with cyclic data structures. For example, if main() holds a shared_ptr to object A, which directly or indirectly holds a shared_ptr back to object A, then object A's use_count() will be 2, and destruction of the main() shared_ptr will leave object A dangling with a use_count() of 1.
The class is a template parameterized on T, the type of the object pointed to. T must meet the smart pointer Common requirements.
#include <boost/smart_ptr.hpp> namespace boost { template<typename T> class shared_ptr { public: typedef T element_type; explicit shared_ptr( T* p=0 ); ~shared_ptr(); shared_ptr( const shared_ptr& ); template<typename Y> shared_ptr(const shared_ptr<Y>& r); // never throws template<typename Y> shared_ptr(std::auto_ptr<Y>& r); shared_ptr& operator=( const shared_ptr& ); // never throws template<typename Y> shared_ptr& operator=(const shared_ptr<Y>& r); // never throws template<typename Y> shared_ptr& operator=(std::auto_ptr<Y>& r); void reset( T* p=0 ); T& operator*() const; // never throws T* operator->() const; // never throws T* get() const; // never throws long use_count() const; // never throws bool unique() const; // never throws void swap( shared_ptr<T>& other ) throw() }; template<typename T, typename U> inline bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b) { return a.get() == b.get(); } template<typename T, typename U> inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b) { return a.get() != b.get(); } }
namespace std { template<typename T> inline void swap(boost::shared_ptr<T>& a, boost::shared_ptr<T>& b) { a.swap(b); } template<typename T> struct less< boost::shared_ptr<T> > : binary_function<boost::shared_ptr<T>, boost::shared_ptr<T>, bool> { bool operator()(const boost::shared_ptr<T>& a, const boost::shared_ptr<T>& b) const { return less<T*>()(a.get(),b.get()); } }; } // namespace std
Specialization of std::swap uses the fast, non-throwing swap that's provided
as a member function instead of using the default algorithm which creates a
temporary and uses assignment.
Specialization of std::less allows use of shared pointers as keys in C++
Standard Library associative collections.
The std::less specializations use std::less<T*> to perform the
comparison. This insures that pointers are handled correctly, since the
standard mandates that relational operations on pointers are unspecified (5.9 [expr.rel]
paragraph 2) but std::less<> on pointers is well-defined (20.3.3 [lib.comparisons]
paragraph 8).
It's still a controversial question whether supplying only std::less is better
than supplying a full range of comparison operators (<, >, <=, >=).
The current implementation does not supply the specializations if the macro name BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION is defined.
The current implementation does not supply the member template functions if the macro name BOOST_NO_MEMBER_TEMPLATES is defined.
typedef T element_type;
Provides the type of the stored pointer.
explicit shared_ptr( T* p=0 );
Constructs a shared_ptr, storing a copy of p, which must have been allocated via a C++ new expression or be 0. Afterwards, use_count() is 1 (even if p==0; see ~shared_ptr).
The only exception which may be thrown by this constructor is std::bad_alloc. If an exception is thrown, delete p is called.
shared_ptr( const shared_ptr& r); // never throws template<typename Y> shared_ptr(const shared_ptr<Y>& r); // never throws template<typename Y> shared_ptr(std::auto_ptr<Y>& r);
Constructs a shared_ptr, as if by storing a copy of the pointer stored in r. Afterwards, use_count() for all copies is 1 more than the initial r.use_count(), or 1 in the auto_ptr case. In the auto_ptr case, r.release() is called.
The only exception which may be thrown by the constructor from auto_ptr is std::bad_alloc. If an exception is thrown, that constructor has no effect.
~shared_ptr();
If use_count() == 1, deletes the object pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. Note that in C++ delete on a pointer with a value of 0 is harmless.
Does not throw exceptions.
shared_ptr& operator=( const shared_ptr& r); template<typename Y> shared_ptr& operator=(const shared_ptr<Y>& r); template<typename Y> shared_ptr& operator=(std::auto_ptr<Y>& r);
First, if use_count() == 1, deletes the object pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1. Note that in C++ delete on a pointer with a value of 0 is harmless.
Then replaces the contents of this, as if by storing a copy of the pointer stored in r. Afterwards, use_count() for all copies is 1 more than the initial r.use_count(), or 1 in the auto_ptr case. In the auto_ptr case, r.release() is called.
The first two forms of operator= above do not throw exceptions.
The only exception which may be thrown by the auto_ptr form is std::bad_alloc. If an exception is thrown, the function has no effect.
void reset( T* p=0 );
First, if use_count() == 1, deletes the object pointed to by the stored pointer. Otherwise, use_count() for any remaining copies is decremented by 1.
Then replaces the contents of this, as if by storing a copy of p, which must have been allocated via a C++ new expression or be 0. Afterwards, use_count() is 1 (even if p==0; see ~shared_ptr). Note that in C++ delete on a pointer with a value of 0 is harmless.
The only exception which may be thrown is std::bad_alloc. If an exception is thrown, delete p is called.
T& operator*() const; // never throws
Returns a reference to the object pointed to by the stored pointer.
T* operator->() const; // never throws T* get() const; // never throws
Both return the stored pointer.
long use_count() const; // never throws
Returns the number of shared_ptrs sharing ownership of the stored pointer.
bool unique() const; // never throws
Returns use_count() == 1.
void swap( shared_ptr<T>& other ) throw()
Swaps the two smart pointers, as if by std::swap.
// The application will produce a series of // objects of type Foo which later must be // accessed both by occurrence (std::vector) // and by ordering relationship (std::set). class Foo { ... }; typedef boost::shared_ptr<Foo> FooPtr; std::vector<FooPtr> foo_vector; std::set<FooPtr> foo_set; // NOT multiset! ... { // creation loop FooPtr foo_ptr ( new Foo( ... ) ); foo_vector.push_back( foo_ptr ); foo_set.insert( foo_ptr ); }
Note that at the termination of the creation loop, some of the FooPtr objects may have use_count()==1 rather than use_count()==2, since foo_set is a std::set rather than a std::multiset. Furthermore, use_count() will be even higher at various times inside the loop, as container operations are performed. More complicated yet, the container operations may throw exceptions under a variety of circumstances. Without using a smart pointer, memory and exception management would be a nightmare.
Revised 10 February, 2001
© Copyright Greg Colvin and Beman Dawes 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright 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.