C++高级——带引用计数的智能指针(shared_ptr,weak_ptr)

带引用计数的智能指针

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

带引用计数的智能指针可以实现多个智能指针管理同一个资源。 通过给每个被管理的资源匹配一个引用计数来实现。当新增一个智能指针指向该资源时,引用计数+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.
全部评论

相关推荐

11-01 20:03
已编辑
门头沟学院 算法工程师
Lambdayo:算法岗是这样的,后端开发的牛马可就没那么幸运啦
点赞 评论 收藏
分享
12-06 10:46
已编辑
上海大学 C#工程师
牛客51133208号:无敌了佬
点赞 评论 收藏
分享
12-08 00:18
电子工程师
四方继保 工程服务岗 月薪税前8000,第一年到手可能在18万左右 211本科
点赞 评论 收藏
分享
评论
点赞
1
分享
牛客网
牛客企业服务