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