boost shared_ptr基本用法介绍

一、介绍

shared_ptr包装了new操作符在堆上分配的动态对象,但他实现的是计数型的智能指针,shared_ptr早期的名字就是counter_ptr,可以自由拷贝和赋值,在任意的地方共享它,当没有代码使用(引用计数为0时)它才删除被包装的动态分配的对象。shared_ptr也可以安全地放到标准容器中,是在STL容器中存储指针最标准的解法。

template<class T>
class shared_ptr
{
 public:
	typedef T element_type; 					//内部类型定义
	shared_ptr();
	template<class Y> explicit shared_ptr(y*p); //构造函数
	template<classY,class D> shared_ptr(Y*p,D d);
	~shared_ptr(); 								//析构函数
	shared_ptr(shared_ptr const &r); 			//拷贝构道
	template<class Y> explicit shared_ptr(std::auto_ptr<Y> &r);
	
	shared_ptr & operator=(shared_ptr const &r); //赋值操作
	template<class Y> shared_ptr & operator=(shared_ptr<Y> const&r); 
	template<class Y> shared ptr & operator=(std::autoptr<y> & r);
	void reset(); 								//重置智能指针
	template<class Y> void reset(Y*p);
	template<class Yclass D> void reset(Y*p, D d);
	
	
	T & operator*() const; 						//操作符重载
	T * operator->() const; 					//操作符重载
	T * get() const; 							//获得原始指针
	bool unique() const; 						//是否唯一
	long use_count() const; 					//引用计数
	operator bool()const; 						//bool值转型
	void swap(shared_ptr &b); 					//交换指针
};

shared_ptr与scoped_ptr同样是用于管理new动态分配对象的智能指针,因此功能上有很多相似之处:它们都重载了*和->操作符以模仿原始指针的行为,提供隐式bool类型转换以判断指针的有效性,get可以得到原始指针(return px),并且没有提供指针算数操作。

shared_ptr<int> spi(new int);
assert(spi);
*spi = 253;
shared_ptr<string> sps(new string("smart"));
assert(sps->size() == 5);

shared_ptr有多种形式构造函数,应用于各种可能的情形:

  • 无参的shared_ptr()创建一个持有空指针的shared_ptr;
  • shared_ptr(Y* p)获得指向类型T的指针p的管理权,同时引用计数置为1.这个构造函数要求Y类型必须能够转换为T类型
  • shared_ptr(shared_ptr const & r)从另外一个shared_ptr获得指针的管理权,同时引用计数加1,结果是两个shared_ptr共享一个指针的管理权;
  • shared_ptr(std::auto_ptr< Y> &r)从另外一个auto_ptr获得指针的管理权,引用计数置为1,同时auto_ptr自动失去管理权;
  • operator=赋值操作符可以从另外一个shared_ptr或auto_ptr获得指针的管理权,其行为同构造函数
  • shared_ptr(Y *p, D d)行为类似shared_ptr(Y *p),但是用参数d指定了析构时定值删除器,而不是简单的delete。

shared_ptr的reset()函数与scoped_ptr也不尽相同。它的作用是将引用计数减1,停止对指针的共享,除非引用计数为0,否则不会发生删除操作。带参数的reset()则是类似相同形式的构造函数,原指针引用计数减1的同时改为管理另一个指针。

shared_ptr有两个专门的函数检查引用计数。unique()检查shared_ptr是指针唯一所有者返回true,use_count()返回当前引用计数。use_count()应该仅用于测试或调试,它不提供高效的操作,而且有可能是不可用的(极少数情形)。

shared_ptr还支持比较运算,可以测试两个shared_ptr的相等或不相等,比较基于内部保存的指针,相当于a.get()==b.get()。shared_ptr还可以使用operator<比较大小。同样基于内部保存的指针,但不提供除operator<之外的比较操作符,这使得shared_ptr可以被用于标准关联容器(set和map)

shared_ptr的类型转换不能使用static_cast之流,只能使用shared_ptr自己提供的转型函数:static_pointer_cast()、const_pointer_cast()、dynamic_pointer_cast()和reinterpret_cast()函数,它们转型后返回的是shared_ptr类型。

如下使用static_pointer_cast ,dynamic_pointer_cast对bad_exception,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);

此外,shared_ptr还支持流输出操作符operator<<,输出内部指针值,方便调试。
代码实现如下:

template<class T, class U> inline bool operator<(shared_ptr<T> const & a, shared_ptr<U> const & b) BOOST_NOEXCEPT
{
    return a.owner_before( b );
}

template<class T> inline void swap(shared_ptr<T> & a, shared_ptr<T> & b) BOOST_NOEXCEPT
{
    a.swap(b);
}

template<class T, class U> shared_ptr<T> static_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT
{
    (void) static_cast< T* >( static_cast< U* >( 0 ) );

    typedef typename shared_ptr<T>::element_type E;

    E * p = static_cast< E* >( r.get() );
    return shared_ptr<T>( r, p );
}

template<class T, class U> shared_ptr<T> const_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT
{
    (void) const_cast< T* >( static_cast< U* >( 0 ) );

    typedef typename shared_ptr<T>::element_type E;

    E * p = const_cast< E* >( r.get() );
    return shared_ptr<T>( r, p );
}

template<class T, class U> shared_ptr<T> dynamic_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT
{
    (void) dynamic_cast< T* >( static_cast< U* >( 0 ) );

    typedef typename shared_ptr<T>::element_type E;

    E * p = dynamic_cast< E* >( r.get() );
    return p? shared_ptr<T>( r, p ): shared_ptr<T>();
}

template<class T, class U> shared_ptr<T> reinterpret_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT
{
    (void) reinterpret_cast< T* >( static_cast< U* >( 0 ) );

    typedef typename shared_ptr<T>::element_type E;

    E * p = reinterpret_cast< E* >( r.get() );
    return shared_ptr<T>( r, p );
}

二、用法示例:

 shared_ptr<int> sp(new int(10); //一个指向整数的shared ptr
 assert(sp.unique)): //现在shared_ptr是指针的唯一持有者
 shared_ptr<int> sp2 - sp; //第二个shared_ptr,拷贝构造函数

//两个shared_ptr相等,指向同一个对象,引用计数为 2 assert(sp sp2 .. sp.use count() 2);

 *sp2=100; //使用解引用操作符修改被指对象
 assert(*sp w*100): //另一个sharedptr也同时被修改
 sp.reset(); //停止 shared_ptr 的使用
 assert(!sp); //sp不再持有任何指针(空指针)

//第二个例子示范了shared_ptr较复杂的用法:
 class shared //一个拥有shared_ptr的类
(
privater:
 //shared_ptr 成员变量
 shared ptr<int> p; 
public:
 shared(shared_ptr<int>P_):P(P_){} //构造承数初始化shared_ptr
 void print() //输出 shared ptr 的引用计数和指向的值
 {
 	cout <<"count:" << p.use_count()
		<<x "v =" <<*p << endl;
 }
1;
//使用shared ptr 作为函数参数
 void print func(shared ptr<int p)
 {
  //同样输出 shared_ptr 的引用计数和指向的值 
  cout << "count;" << p.use_count()
	<<" v=" <<*p <<endl;

 int main()
 {
	 shared ptr<int>p(new int(100)):
	 shared s1(p),s2(p); //构造两个自定义类
	
	 s1.print();
	 s2.print();
	
	 *p = 20: //修改shared_ptr所指的值
	
	 print_func(p);
	
	 s1.print();
 }

运行结果:

count:3 v=100
count:3 v=100
count:4 v=20
count:3 v=20

这段代码定义了一个类和一个函数,两者都接受share_ptr 对象作为参数,特别注意的是我们没有使用引用的方式传递参数,而是直接拷贝,就像是在使用一个元素指针,,share_ptr支持这样的用法。
在声明了share_ptr和两个shared示例后,指针被他们所共享因此引用计数为3,print_func()函数内部拷贝了一个share_ptr对象,因此引用计数再增加1,当退出函数时拷贝自动析构,引用计数又减为3。

三、工厂函数make_shared

share_ptr提供了一个自由工厂函数make_shared(),来消除显示的new调用,make_shared()函数接受若干个参数,然后把他们传递给类型T的构造函数,创建一个share_ptr的对象并返回。通常make_shared()函数比直接创建share_ptr对象的方式快且高效。因为它内部仅分配一次内存,消除了share_ptr构造时的开销。

int main()
{
	shared_ptr<string> sp = make_shared<string>("make_shared");
	shared_ptr<vector<int>> spv = make_shared<vector<int> >(10,2);
	assert(spv->size() == 10);
}

四、应用于标准容器

有两种方法可以将share_ptr应用于标准容器(或者容器适配器等其他容器),一种方法是将容器作为share_ptr管理的对象,即share_ptr<list>,使容器可以安全地共享。这个比较常用。
另一种是将share_ptr作为容器的元素。如vector<shared_ptr>,因为share_ptr支持拷贝语义和比较操作,符合容器对元素的要求,所以可以在容器中安全地容纳元素的指针而不是拷贝

#include <boost/make shared.hpp>
int main()
{
 typedef vector<shared_ptr<int>> vs; //一个持有shared_ptr 的标准容器类型
 vs v(10); 							//声明一个拥有10个元素的容器。元素被
									//初始化为空指针

 int i = 0;
 for(vs::iterator pos = v.begin():pos != v.end(): ++pos){
	(*pos) = make_shared<int>(++i); //使用工厂函数赋值
	 cout << *(*pos)<<","; 		//输出值
 }
 cout << endl;

 shared_ptr<int> p = v[9];
 *p = 100;
 cout <<*v[9] << endl;
 }

引用资料:
《Boost程序库完全开发指南–深入C++“准”标准库(第2版)》
作者:罗剑锋

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值