初學c++引用計數器

   以後會多寫些本質論的文章,這樣可以更好的引導自己去深入思考。

       爲什麼要用引用計數? 

       場景:代碼裏X是一個非常重要的資源,模塊A,B,C都有對其指針的引用,那麼爲了不出現內存泄露,常規的代碼我們要怎麼寫?

               1. A 模塊用完X時,需要檢查B,C是否還在引用X,如果B,C有一個在用,那麼X只要刪除掉對A的引用就可以了,

                  如果B,C對A都已經沒有引用了,那麼A需要刪除對X的引用時,要同時清除掉X。

               2.同樣B,C在用完X時,也要重複做1裏面的事情。

                 這樣,代碼將會多了許多的邏輯判斷,同時模塊B,C還需要對模塊A提供查詢是否在引用X的接口。

        可以不這麼噁心嗎?

        思考:能否A在釋放X前,不需要知道是誰在引用X,只要知道有多少人在引用X?

        回答:是的,如果只有我用X,那麼我就直接刪除,如果還有其他人用,我就什麼都不管,只要去除掉對X的引用就可以了。  情況就會變的好一些。

        那麼如何做到能知道資源的引用次數那?

        這就需要對每一個資源X的都有一個的計數,這個計數是和資源X的生命週期息息相關的。

        那麼如何來管理這個計數?怎麼能在有模塊引用資源X的時候,計數++,模塊釋放資源X的時候計數--那?

        這個就有一定難度了,引用的方式會有很多種,比如  A = X;   A.push_back(X);  A[100] = X; ...

        當然我們可以在代碼裏的每一處增加和釋放資源引用的地方,都加上代碼count++,count--;但這亦然很麻煩,維護成本很高。

        如何簡單些?

        能否把對資源的引用和釋放,看成是對一個類的拷貝和銷燬來完成? 弄一個代理類,裏面封裝好計數和資源X。

        把所有對資源X的引用都理解成對代理類的引用,對代理類的引用都理解成對代理類的拷貝,對代理的釋放就是銷燬代理類。

        這樣我們只需要在代理類的拷貝函數裏count++ , 代理類的析構做count--就好了。

        如果代理類的資源引用計數count 減爲0,就看成所有人都釋放了對資源X的引用,這時由代理類來完成對資源的銷燬。

        這樣下來,事情就簡化了很多。 所以學會抽象是多麼重要的一件事情。


下面詳解代碼

#include<iostream>
#include<string>
using namespace std;
template<class T>
class Handle
{
public:
	//複製構造函數
	Handle(T *p = nullptr) :ptr(p), use(new size_t(1))  //初始化引用計數器爲1
	{

	}
	Handle(const Handle &h) :ptr(h.ptr), use(h.use)  //複製構造函數,沒調用一次+1
	{
		++*use;
	}

	Handle &operator=(const Handle &);  //重載=操作符  引用計數器+1


	T &operator*();//重載*運算符
	T *operator->();//重載->運算符
	const T &operator*() const;
	const T *operator->() const; 

	~Handle() //析構說明對象已經銷燬,放棄當前引用資源,so -1
	{
		rem_ref();
	}



private:
	T *ptr;//模擬公共資源
	size_t *use;//計數器
	void rem_ref()  //引用計數器-1
	{
		if (--*use == 0)
		{
			delete ptr;  //刪除資源
			delete use;  
		}



	}
};
template<class T>
Handle<T>&  Handle<T>::operator = (const Handle &rhs)
{
	++*rhs.use;
	rem_ref();//如果開始引用了其他資源,由於又要引用其他資源,那麼-1表示放棄引用當前資源
	ptr = rhs.ptr;
	use = rhs.use;
	return *this;
	  
}
template<class T>
inline T& Handle<T>::operator*()
{
	if (ptr)
	{
		return *ptr;
	}
	throw std::runtime_error("dereference of unbound Handle");

}
template<class T>
inline T *Handle<T>::operator->()
{
	if (ptr)
		return ptr;
	throw std::runtime_error("access through unbound Handle");
}

template<class T>
const T &Handle<T>::operator->() const
{
	if (ptr)
		return *ptr; 
	throw std::runtime_error("dereference of unbound Handle");


}

template<class T>
const T *Handle<T>:: operator ->() const
{
	if (ptr)
		return ptr;
	throw std::runtime_error("access through unbound Handle");
}

int main()
{
	Handle<int>  hp(new int(42)); //這裏 42表示資源 




	{
		Handle <int> hp2(hp);//調用複製構造函數進行初始化,將共同引用42
		cout << *hp << "   " << *hp2 << endl;
		*hp2 = 10;//公有資源變成10
	}
	cout << *hp << endl;

}
//執行main 後引用計數器將變成0,刪除資源和引用計數器





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章