Shared_ptr is the most valuable and important component in the boost. smart_ptr library. Like scoped_ptr, it encapsulates the new operator to allocate dynamic objects on the stack, But it implements a reference-count smart pointer that can be freely copied and assigned values, share it anywhere. When the reference count value is 0, that is, if no code is used, it will automatically delete the objects of the allocated resources.
Shared_ptr can be securely placed in the standard container, and makes up for the auto_ptr's defect that the pointer STL container element cannot be transferred because of the transfer semantics. C ++ has seen many reference-counting smart pointers in history, but none of them are comparable to boost: shared_ptr. In the past, now, it will be the best in the future.
Class Abstract:
template<class T> class shared_ptr{private: // Borland 5.5.1 specific workaround typedef shared_ptr<T> this_type;public: typedef T element_type; typedef T value_type; typedef T * pointer; typedef typename boost::detail::shared_ptr_traits<T>::reference reference; shared_ptr(); template<class Y> explicit shared_ptr( Y * p ); template<class Y, class D> shared_ptr(Y * p, D d); template<class Y, class D, class A> shared_ptr( Y * p, D d, A a ); template<class Y> explicit shared_ptr(weak_ptr<Y> const & r); template<class Y> shared_ptr( weak_ptr<Y> const & r, boost::detail::sp_nothrow_tag ); template<class Y> shared_ptr( shared_ptr<Y> const & r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() ); shared_ptr( shared_ptr<Y> const & r ); template< class Y > shared_ptr( shared_ptr<Y> const & r, T * p ); template<class Y> shared_ptr(shared_ptr<Y> const & r, boost::detail::static_cast_tag); template<class Y> shared_ptr(shared_ptr<Y> const & r, boost::detail::const_cast_tag); template<class Y> shared_ptr(shared_ptr<Y> const & r, boost::detail::dynamic_cast_tag); template<class Y> shared_ptr(shared_ptr<Y> const & r, boost::detail::polymorphic_cast_tag); template<class Y> explicit shared_ptr(std::auto_ptr<Y> & r); template<class Ap> explicit shared_ptr( Ap r, typename boost::detail::sp_enable_if_auto_ptr<Ap, int>::type = 0 ); shared_ptr & operator=( shared_ptr const & r ) // never throws template<class Y> shared_ptr & operator=(shared_ptr<Y> const & r) //never throw template<class Y> shared_ptr & operator=( std::auto_ptr<Y> & r ); template<class Ap> typename boost::detail::sp_enable_if_auto_ptr< Ap, shared_ptr & >::type operator=( Ap r ); shared_ptr( shared_ptr && r ); template<class Y> shared_ptr( shared_ptr<Y> && r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() ) shared_ptr( shared_ptr<Y> && r ); shared_ptr & operator=( shared_ptr && r ); // never throws template<class Y> shared_ptr & operator=( shared_ptr<Y> && r ) // never throws void reset() ;// never throws in 1.30+ template<class Y> void reset(Y * p) // Y must be complete template<class Y, class D> void reset( Y * p, D d ); template<class Y, class D, class A> void reset( Y * p, D d, A a ); template<class Y> void reset( shared_ptr<Y> const & r, T * p ); reference 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 void swap(shared_ptr<T> & other);// never throws template<class Y> bool _internal_less(shared_ptr<Y> const & rhs) const; void * _internal_get_deleter( boost::detail::sp_typeinfo const & ti ); bool _internal_equiv( shared_ptr const & r ) const;private: template<class Y> friend class shared_ptr; template<class Y> friend class weak_ptr; T * px; // contained pointer boost::detail::shared_count pn; // reference counter}; // shared_ptr
Shared_ptr reloads the * and-> operators to mimic the behavior of the original pointer, and provides implicit bool type conversion to determine whether the pointer is valid. Get () can get the original pointer without providing pointer arithmetic operations. It can copy, assign values, or compare shared_ptr, and is the most intelligent smart pointer.
Shared_ptr has multiple forms of constructor, which can be applied to various possible situations:
1. shared_ptr () without parameters creates a shared_ptr with null pointers
2. shared_ptr (y * P) obtains the management right of pointer P pointing to type T, and sets the reference count to 1. This constructor requires that the T type be converted to the Y type.
3. shared_ptr (shared_ptr const & R) obtains the pointer management right from another shared_ptr, and the reference count is 1. The result is that two shared_ptr share the management right of one pointer.
4. shared_ptr (STD: auto <Y> & R) obtains the pointer management right from an auto_ptr, sets the reference count to 1, and auto_ptr automatically loses the management right.
5. Operator = the assignment operator can obtain the pointer management right from another shared_ptr or auto_ptr, and its behavior is the same as that of the constructor.
6. The shared_ptr (y * P, d) behavior is similar to shared_ptr (y * P). However, the parameter D is used to specify the custom Delete tool for the destructor, rather than the simple Delete tool.
Shared_ptr's reset () function is to reduce the reference count by 1 and stop sharing the pointer. Unless the reference count is 0, no deletion operation will be performed. The reset () with parameters is similar to the constructor in the same form. The original pointer references the Count minus 1 and changes it to manage another pointer.
Shared_ptr has two functions to check the reference count. Unique () returns true when shared_ptr is the unique owner of the pointer (the behavior is similar to auto_ptr or scoped_ptr), use_count () returns the reference count of the current pointer. But be careful, use_count () is only used for testing or debugging. It does not provide efficient operations and may sometimes be unavailable. However, unique () is reliable and can be used at any time, and is faster than use_count () = 1.
Shared_ptr supports comparison. You can test whether two shared_ptr values are equal or not equal. The comparison is based on internally saved pointers, which is equivalent to a. Get () = B. Get (). You can also use operator <to compare the size, which is also based on the internally saved pointer, but does not provide a comparison character other than it, so that shared_ptr can be applied to standard associated containers (set and map ):
Typedef shared_ptr <string> sp_t;
Map <sp_t, int> m; // standard ing container
Sp_t Sp (new string ("one "));
M [Sp] = 111;
The type conversion of pointers is useful when writing multi-state code based on virtual functions, such as converting a base class pointer to an inherited class pointer or vice versa (converting an inherited class pointer to a base class pointer ). However, shared_ptr cannot use a format such as static_cast <t *> (P. Get. This will cause the transformed pointer to be incorrectly managed by shared_ptr. To support this usage, shared_ptr provides transformation functions like static_pointer_cast <t> (), const_pointer_cast <t>, and dynamic_pointer_cast <t>, but returns shared_ptr after transformation.
For example, the following code uses dynamic_pointer_cast to convert a shared_ptr <STD: exception> down to a shared_ptr <bad_exception>, and then uses static_pointer_cast to reset it to shared_ptr <STD: exception>;
Shared_ptr <STD: exception> SP1 (New bad_exception ("error "));
Shared_ptr <bad_exception> SP2 = dynamic_pointer_cast <bad_exception> (SP1 );
Shared_ptr <STD: exception> SP3 = static_pointer_cast <STD: exception> (SP2 );
Assert (SP3 = SP1 );
Shared_ptr also supports the stream output Operator <, which outputs internal pointer values for convenient debugging.
Example:
#include <iostream>#include <boost/smart_ptr.hpp>using namespace boost;using namespace std;class shared //define a custom class{ public: shared(shared_ptr<int> p):_p(p){} void print() { cout << "count: " << _p.use_count() << " v= " << *_p << endl; } private: shared_ptr<int> _p;};void print_func(shared_ptr<int> p){ cout << "count: " << p.use_count() << " v= " << *p << endl;}int main(){ /* /*example1 shared_ptr<int> sp(new int(10));//a smart_ptr pointed to int assert(sp.unique()); //shared_ptr is the only owner of pointer shared_ptr<int> sp2 = sp; //the second shared_ptr,copy construct assert(sp == sp2 && sp.use_count() == 2); //Two shared_ptr equal, pointing in the same object, reference counting is 2 *sp2 = 100; //now print *sp2 assert(*sp == 100); sp.reset();// assert(!sp);//sp now is empty cout << "no problem." << endl; */ /*example2*/ shared_ptr<int> p(new int(100)); shared s1(p),s2(p);//custom shared class object s1.print(); //3 s2.print();//3 *p = 20; //modify the value of the object which p point to print_func(p);//display use_count 4 s1.print();//3 }
Running result:
Count: 3 V = 100
Count: 3 V = 100
Count: 4 V = 20
Count: 3 V = 20
Note: We do not use the reference method to pass the parameter, but directly copy it. It is like using an original pointer. shared_ptr supports this usage.
After the cmd_ptr and two shared class instances are declared, the pointer is shared by them, so the reference count is 3. The print_fun () function copies a shared_ptr object internally, so the reference count is increased by 1. When exiting, the copy function automatically analyzes the structure, and the reference count is restored to 3.