带引用计数的智能指针

什么是带引用计数的智能指针,有什么用的?

带引用计数的智能指针可以实现多个智能指针管理同一个资源。 通过给每个被管理的资源匹配一个引用计数来实现。当新增一个智能指针指向该资源时,引用计数+1,当减少一个智能指向该资源是,引用计数-1,知道引用计数为0时,资源被释放掉。

下面我们就来看一个简单的智能指针的代码:
首先是对资源引用计数的类。

template<typename T> 
class RefCnt
{
   
public:
	RefCnt(T *ptr = nullptr):mptr (ptr)
	{
   
		if (mptr != nullptr)
			mcount = 1;
	}
	void addRef(){
    mcount++; }//增加引用计数
	int delRef(){
    return --mcount;}//减少引用计数
private :
	T *mptr;
	int mcount;
};

然后是主角,智能指针类。

template<typename T>
class Csmartptr
{
   
public:
	Csmartptr(T* ptr = nullptr) :mptr(ptr) 				
	{
   
		mpRefCnt = new RefCnt<T>(mptr);
	}
	/*Csmartptr(const Csmartptr<T> &src) { mptr = new T(*src .mptr) ; }*/
	~Csmartptr() 
	{
    
		if (0 == mpRefCnt->delRef () )
		{
   
			delete mptr; 
			mptr = nullptr;
		}
	}
	T& operator*() {
    return *mptr; }
	T* operator->{
   return mptr; }

	Csmartptr(const Csmartptr<T> &src):mptr(src.mptr)mpRefCnt(src.mpRefCnt)
	{
   
		if (mptr != nullptr)
		mpRefCnt->addRef() ;
	}

	Csmartptr<T>& operator= (const Csmartptr<T> &src)
	{
   
		if (this == &src)
			return *this;
I		//删除原有对象指向的资源
		if (0 == mpRefCnt->delRef () )
		{
   
			delete mptr;
		}
		mptr = src.mptr;
		mpRefCnt = src.mpRefCnt ;
		mpRefCnt->addRef () ;
		return *this;
	}

private:
	T* mptr;//指向资源的指针
	RefCnt<T> *mpRefCnt;//指向该资源引用计数对象的指针
};

这时我们再看如下代码便可以实现裸指针的功能啦,*ptr2 和 *ptr3都是20。

CSmartPtr<int> ptr1 (new int) ;
CSmartPtr<int> ptr2(ptr1) ;
CSmartPtr<int> ptr3;
ptr3 = ptr2;
*ptr1 = 20;
cout << *ptr2 << " " << *ptr3 << endl ;

shared_ptr与weak_ptr

shared_ptr与我刚刚写过的智能指针一样,都是强智能指针,它们可以改变资源的引用计数,可以改变资源。

与强智能指针对应的就是弱智能指针weak_ptr,它不会改变资源的引用计数,不能改变资源,只是一个观察者。

它们的关系是弱智能指针观察强智能指针,强智能指针管理资源。

那么又有问题了?有了强智能指针还要弱智能指针干嘛???

下面我们来看一下代码:
假设有以下两个类。

class A
{
   
public:
	A(){
   cout<<"A()<<endl;}
	~A() {
    cout << "~A()<< endl; }
	shared_ptr<B>_ ptrb;
};
class B
public:
	B() {
    cout << "B()" << endl; }
	~B() {
    cout << "~B()" << endl; }
	shared_ptr<A>_ ptra;
};

再来看应用的主函数:

int main()
{
   
	shared_ptr<A> pa(new A()) ;
	shared_ptr<B> pb(new B()) ;
	pa->_ptrb = pb;
	pb->_ptra = pa;
	cout << pa.use_count() << endl ;
	cout << pb.use_count() << endl ;
	return 0;
}

此时打印发现,A、B两个资源的引用计数都是2,且并未析构!内存泄露了!

经过画图,我们理一下此时A、B复杂的关系:

可以看到,A、B两个资源之间由指针形成了一个循环。而pa、pb的析构只能使引用计数-1,2-1=1!=0,所以A、B资源并未析构,这也是强智能指针的交叉引用问题。

这时就需要我们的弱智能指针登场了。
只要把类型定义为weak_ptr<B> _ptrb;就没有问题了。

但是又有新问题了:弱智能指针无法改变资源啊。

弱智能指针有个lock方法,可以提升为强智能指针。当弱智能指针指向的资源被释放了,就会返回nullptr,以下是个使用示例:

shared_ptr<A> ps = _ptra.lock();
if (ps != nullptr)
	ps->funA();

睡了睡了,明天再更博客。

参考文献

[1] 施磊.腾讯课堂——C++高级.图论科技,2020.7.