shared_ptr是boost.smart_ptr库中最具价值、最有份量的组成部分。它与scoped_ptr一样包装了new操作符在堆上分配动态对象,但它实现的是引用计数(reference-count)型智能指针,可以被自由地拷贝和赋值,在任意的地方共享它。当引用计数值为0,也即没有代码使用它时它会自动删除被分配资源的对象。
shared_ptr可以安全地放到标准容器中,并弥补了auto_ptr因为转移语义而不能把指针STL容器元素的缺陷。C++历史上出现过很多引用计数型的智能指针,但没有一个比得上boost::shared_ptr的,过去,现在,将来它都是最好的。
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重载了*和->操作符以模仿原始指针的行为,同时提供隐式bool类型转换判断指针是否有效。get()可以得到原始指针,没有提供指针算术操作。它可以正常地拷贝,赋值,也可以进行shared_ptr之间的比较,是最智能的智能指针。
1,无参的shared_ptr()创建一个持有空指针的shared_ptr
2,shared_ptr(Y *p)获得指向类型T的指针p的管理权,同时引用计数置为1。这个构造函数要求T类型必须能够转换成Y类型
3,shared_ptr(shared_ptr const &r)从另外一个shared_ptr获得指针的管理权,同时引用计数为1,结果是两个shared_ptr共享一个指针的管理权。
4,shared_ptr(std::auto<Y> &r)从一个auto_ptr获得指针的管理权,引用计数置为1,同时auto_ptr自动失去管理权。
5,operator=赋值操作符可以从另外一个shared_ptr或auto_ptr获得指针的管理权,其行为同构造函数
6,shared_ptr(Y *p,D d)行为类似shared_ptr(Y *p),但使用参数d指定了析构时的定制删除器,而不是简单的delete。
shared_ptr的reset()函数是将引用计数减1,停止对指针的共享,除非引用计数为0,否则不会发生删除操作。带参数的reset()则类似相同形式的构造函数,原指针引用计数减1的同时改为管理另外一个指针。
shared_ptr有两个函数来检查引用计数,unique()在shared_ptr是指针的唯一所有者时返回true(这时的行为类似auto_ptr或scoped_ptr),use_count()返回当前指针的引用计数。不过小心了,use_count()仅仅用于测试或者调试,它不提供高效的操作,而且有时可能是不可用的。但是unique()是可靠的,任何时候都可以用,而且比use_count() == 1速度更快。
shared_ptr支持比较运算,可以测试两个shared_ptr的相等或不相等,比较基于内部保存的指针,相当于a.get() == b.get() 。还可以使用operator<比较大小,同样基于内部保存的指针,但不提供除它以外的比较符,这使得shared_ptr可以被应用于标准关联容器(set和map):
typedef shared_ptr<string> sp_t;
map<sp_t,int > m; //标准映射容器
sp_t sp(new string("one"));
m[sp] = 111;
在编写基于虚函数的多态代码时指针的类型转换很有用,比如把一个基类指针转换成一个继承类指针或者反过来(继承类指针转换成基类指针)。但对于shared_ptr不能使用诸如static_cast<T *>(p.get())的形式。这将导致转型后的指针无法再被shared_ptr正确管理。为了支持这种用法,shared_ptr提供了类似的转型函数static_pointer_cast<T>() ,const_pointer_cast<T>, dynamic_pointer_cast<T>类似,但它返回的是转型后的shared_ptr。
例如,下面的代码使用dynamic_pointer_cast把一个shared_ptr<std::exception>向下转型为一个shared_ptr<bad_exception>,然后又用static_pointer_cast重置转为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还支持流输出操作符operator<<,输出内部的指针值,方便调试。
使用示例:
#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 }
运行结果:
count: 3 v= 100
count: 3 v= 100
count: 4 v= 20
count: 3 v= 20
注意,我们没有使用引用方式传递参数,而是直接拷贝,就像是使用一个原始指针,shared_ptr支持这样的用法。
在声明了share_ptr和两个shared类实例后,指针被它们所共享,因此引用计数为3。print_fun()函数内部拷贝了一个shared_ptr对象,因此引用计数再增加1,退出的时候拷贝自动析构,引用计数又恢复到了3