智能指针shared_ptr组件的使用

来源:互联网 发布:update sql 多项条件 编辑:程序博客网 时间:2024/05/02 01:07

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之间的比较,是最智能的智能指针。

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

 

原创粉丝点击