Boost开发指南-3.7intrusive_ptr

intrusive_ptr

intrusive_ptr也是一种引用计数型智能指针,但与之前介绍的 scoped_ptr,shared_ptr 不同,需要额外增加一些的代码才能使用。它的名字可能会给人造成误解,实际上它并不一定要修改代理对象的内部数据。

如果现存代码已经有了引用计数机制管理的对象,那么 intrusive_ptr 是一个非常好的选择,可以包装已有对象从而得到与shared_ptr类似的智能指针。

类摘要

template<class T>
class intrusive_ptr 
{
public:
   typedef T element_type; //被代理的对象
   intrusive_ptro(); //构造函数
   intrusive_ptr(T * p, bool add_ref = true);
   intrusive_ptr(intrusive_ptr const & r);
   template<class Y> intrusive_ptr(intrusive_ptr<Y> const & r);
   
   ~intrusive_ptr():
  
   intrusive_ptr & operator=(intrusive_ptr const &r);
   template<class Y> intrusive_ptr & operator=(intrusive_ptr<Y> const & r);
   intrusive_ptr & operator=(T * r);
  
   void reset(); //重置指针
   void reset(T * r);
   void reset(T * r, bool add_ref);
   
   T & operator*() const; //操作符重载
   T * operator->() const;
   explicit operator bool() const;
   
   T* get() const;
   T * detach();
   void swap(intrusive__ptr & b);
};

因为intrusive_ptr也是引用计数型指针,所以它的接口与shared_ptr很像,也同样支持比较和static_pointer_cast ()、dynamic_pointer_cast()等转型操作,但它自己不直接管理引用计数,而是调用下面两个函数来间接管理:

void intrusive_ptr_add_ref(T * p); //增加引用计数
void intrusive_ptr_release(T * p); //减少引用计数

intrusive_ptr的构造函数和reset()还多出一个add_ref参数,表示是否增加引用计数,如果add_refm=true,那么它就相当于weak_ptr,只是简单地观察对象。

用法

假设我们已经有了一个自己实现引用计数的类counted_data:

struct counted_data //自己实现引用计数
{
	int m_count = 0; //引用计数
	... //其他数据类型
};

为了让intrusive_ptr能够管理counted_data,我们需要实现它要求的两个回调函数:

void intrusive_ptr_add_ref(counted_data* p) //增加引用计数
{
	++p->m_count;
}

void intrusive_ptr_release(counted_data* p) //减少引用计数
{
	if (--p->m_count == 0)
	{
		delete p; //引用计数为0 则删除指针
	}
}

注意:在 intrusive_ptr_release()函数里必须检查引用计数,因为intrusive_ptr不负责实例的销毁,这个工作必须由我们自己完成。

实现intrusive_ptr_release()和intrusive_ptr_release()后intrusive_ptr就可以管理counted_data了,示范代码如下:

int main()
{
	typedef intrusive_ptr<counted_data> counted_ptr; //类型定义

	counted_ptr p(new counted_data); //创建智能指针
	assert(p); //bool转型
	assert(p->m_count == 1); //operator->

	counted_ptr p2(p); //指针拷贝构造
	assert(p->m_count == 2); //引用计数增加

	counted_ptr weak_p(p.get(), false); //弱引用
	assert(weak_p->m_count == 2); //引用计数不增加

	p2.reset(); //复位指针
	assert(!p2); //p2不持有指针
	assert(p->m_count == 1); //引用计数不增加

} //对象被正确析构

可以看到,只需要编写少量的代码,我们就可以复用既存的数据结构,获得一个与shared_ptr 用法几乎一样的智能指针,而且并没有增加多余的开销,这在某些对性能要求比较苛刻的场景里非常有用。

但大多数情况下shared_ptr 完全不必增加新代码,而且提供了更多的灵活性,使用intrusive_ptr前必须要确定它能够带来足够多的好处。

引用计数器

为了简化实现引用计数的工作, intrusive_ptr在头文件<boost/smart_ptr/intrusive_ref_counter.hpp>里定义了一个辅助类intrusive_ref_counter,声明如下:

template<typename DerivedT,
         typename CounterPolicyT = thread_safe_counter>
class intrusive_ref_counter
private:
   typedef typenamie counterPolicyT::type counter_type;
   mutable counter_type m_ref_counter;
public:
   intrusive_ref_counter();
   unsigned int use_count() const;
protected:
   ~intrusive_ref_counter() = default;
   friend void intrusive_ptr_add_ref(const intrusive_ref_counter* p);
   friend void intrusive_ptr_release(const intrusive_ref_counter* p);
);

intrusive_ref_counter内部定了一个计数器变量m_ref_counter,使用模板参数CounterPolicyT配置策略类实现了计数的增减,缺省的策略是线程安全的thread_safe_counter。

intrusive_ref_counter需要被继承使用,这样子类就会自动获得引用计数的能力,之前的counted_data可以简化如下:

struct counted_data2 : public intrusive_ref_counter<counted_data2>
{
	...
};

int main()
{
	typedef intrusive_ptr<counted_data2> counted_ptr; //类型定义

	counted_ptr p(new counted_data2); //创建智能指针
	assert(p); //bool转型
	assert(p->use_count() == 1); //operator->
} //对象被正确析构

代码示例

#include <iostream>
using namespace std;

#include <boost/smart_ptr.hpp>
using namespace boost;

//

struct counted_data
{
	// ...
	int m_count = 0;
	~counted_data()
	{
		cout << "dtor" << endl;
	}
};

void intrusive_ptr_add_ref(counted_data* p)
{
	++p->m_count;
}

void intrusive_ptr_release(counted_data* p)
{
	if (--p->m_count == 0)
	{
		delete p;
	}
}

//
#include <boost/smart_ptr/intrusive_ref_counter.hpp>

struct counted_data2 : public intrusive_ref_counter<counted_data2>
{
	~counted_data2()
	{
		cout << "dtor2" << endl;
	}
};
//

int main()
{
	typedef intrusive_ptr<counted_data> counted_ptr;

	counted_ptr p(new counted_data);
	assert(p);
	assert(p->m_count == 1);

	counted_ptr p2(p);
	assert(p->m_count == 2);

	counted_ptr weak_p(p.get(), false);
	assert(weak_p->m_count == 2);

	p2.reset();
	assert(!p2);
	assert(p->m_count == 1);

	{
		typedef intrusive_ptr<counted_data2> counted_ptr;

		counted_ptr p(new counted_data2);
		assert(p);
		assert(p->use_count() == 1);

	}
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阳光开朗男孩

你的鼓励是我最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值