真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

RAII和模擬實(shí)現(xiàn)智能指針-創(chuàng)新互聯(lián)

RAII指的就是資源分配即初始化,它的作用就是定義一個(gè)類來封裝資源的分配和釋放,在構(gòu)造函數(shù)完成資源的分配和初始化,在析構(gòu)函數(shù)完成資源的清理,可以保證資源的正確初始化和釋放。它是一種技術(shù)。

  • 為什么要使用RAII?

在堆上分配空間時(shí),我們必須很仔細(xì)的申請并給出相應(yīng)的釋放語句,但是隨著程序的復(fù)雜度增大,判斷、循環(huán)、遞歸這樣的語句會(huì)讓程序走向不確定,很有可能出現(xiàn)申請了沒釋放,申請了多次釋放。所以我們定義了一個(gè)類來封裝資源的分配和釋放。

  • 那么什么叫智能指針呢?

智能指針是利用了RAII(資源獲取即初始化)的技術(shù)對普通的指針進(jìn)行封裝,這使得智能指針實(shí)質(zhì)是一個(gè)對象,行為表現(xiàn)的卻像一個(gè)指針。

  • 智能指針的分類:

1、AutoPtr     (在函數(shù)庫中都是小寫加下劃線,比如AutoPtr 函數(shù)庫中為auto_ptr)

template

class AutoPtr
{
public:
	AutoPtr(T* ptr=NULL):_ptr(ptr){}
	AutoPtr(AutoPtr& t)
	{
	    _ptr=t._ptr;
	    t._ptr=NULL;
	}
	AutoPtr& operator=(AutoPtr& t)
	{
		if(_ptr!=t._ptr)
		{
			if(_ptr){	delete _ptr;	}
			_ptr=t._ptr;
			t._ptr=NULL;
		}
		return *this;
	}
	T& operator*(){	return *_ptr;}
	T* operator->(){return _ptr;}

	~AutoPtr(){ if(_ptr)	{      delete _ptr;     }  }
private:
	T* _ptr;
};

AutoPtr可以new出空間后,不必delete,出了作用域后會(huì)自動(dòng)釋放。

表面上這看似完美,可現(xiàn)實(shí)并不是這樣。它無法像指針那樣同一塊空間被多個(gè)指針指向,它只能有一個(gè)指針指向一塊空間,當(dāng)發(fā)生拷貝構(gòu)造或者賦值運(yùn)算符重載時(shí),它會(huì)釋放原先的指針。

2、ScopedPtr

ScopedPtr實(shí)際上就是把AutoPtr的拷貝構(gòu)造和賦值運(yùn)算符的重載寫成私有的,不讓用戶訪問,這樣就不會(huì)出現(xiàn)同一塊空間被多個(gè)指針指向,但是這畢竟是治標(biāo)不治本。

3、SharedPtr

template 
class SharedPtr
{
public:
	SharedPtr(T* ptr=NULL)
		:_ptr(ptr)
		,_pcount(new int(1))
	{}
	SharedPtr( SharedPtr& t)
	{
		_ptr=t._ptr;
		_pcount=t._pcount;
		(*_pcount)++;
	}
	SharedPtr& operator=(SharedPtr& t)
	{
		if(_ptr!=t._ptr)
		{
			if(--(*_pcount)==0)
			{
				delete _ptr;
				delete _pcount;
			}
			_ptr=t._ptr;
			_pcount=t._pcount;
			++(*p_count);
		}
		return *this;
	}
	T& operator*(){	return *_ptr;	}
	T* operator->(){	return _ptr;	}
	~SharedPtr()
	{
		if(--(*_pcount)==0)
		{
			delete _ptr;
			delete _pcount;
		}
	}
private:
	T* _ptr;
	int* _pcount;   
};

為什么_pcount的類型是int*類型?

如果_pcount是int類型的,那么構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)和賦值運(yùn)算符重載的代碼應(yīng)為:

SharedPtr(T* ptr = NULL):_ptr(ptr), _pcount(1){}
SharedPtr(SharedPtr& t)
{
_ptr = t._ptr;
_pcount = t._pcount;
(_pcount)++;
}
SharedPtr& operator=(SharedPtr& t)
{
    if (_ptr != t._ptr)
    {
	if (--(_pcount) == 0)
	{
	    delete _ptr;
	 }
	_ptr = t._ptr;
	_pcount = t._pcount;
	++(_pcount);
    }
    return *this;
   }
SharedPtr s = new int(1);          //引用計(jì)數(shù)為1
SharedPtr s1(s);                //引用計(jì)數(shù)為2(s的引用計(jì)數(shù)仍為1)
SharedPtr s2=new int (2);
s=s2;
cout<<*s1<

int類型有幾個(gè)指針就會(huì)在棧上開辟幾個(gè)_pcount。而int*類型時(shí),只在堆上開辟1塊空間來保存*_pcount的值,拷貝構(gòu)造和賦值時(shí)都用的_pcount的地址取值后進(jìn)行加減。

那為什么不用static int類型的呢?
看下面的例子:

SharedPtr s1 = new int(1);             
SharedPtr s2(s1); 
SharedPtr s3 = new int(1);             
SharedPtr s4(s3);

那么此時(shí)的引用計(jì)數(shù)變?yōu)榱?,應(yīng)為_pcount現(xiàn)在是所有對象共享的,定義一個(gè)對象就會(huì)+1,而我們的本意是讓s1和s2共享一個(gè)_pcount,s3和s4共享一個(gè)_pcount。而int*可以做到這一點(diǎn),當(dāng)構(gòu)造s1時(shí)申請一塊空間實(shí)現(xiàn)引用計(jì)數(shù),構(gòu)造s2時(shí)引用計(jì)數(shù)+1。構(gòu)造s3時(shí)再申請一塊空間實(shí)現(xiàn)引用計(jì)數(shù),構(gòu)造s4時(shí)引用計(jì)數(shù)+1;

SharedPtr實(shí)現(xiàn)了引用計(jì)數(shù),它支持復(fù)制,復(fù)制一個(gè)SharedPtr的本質(zhì)是對這個(gè)智能指針的引用次數(shù)加1,而當(dāng)這個(gè)智能指針的引用次數(shù)降低到0的時(shí)候,該對象自動(dòng)被析構(gòu)。

這樣的SharedPtr依然存在著問題。

①如果shared_ptr引用關(guān)系中出現(xiàn)一個(gè)環(huán),那么環(huán)上所述對象的引用次數(shù)都肯定不可能減為0,那么也就不會(huì)被刪除。

struct ListNode
{
    int _value;
    SharedPtr _next;
    SharedPtr _prev;
    ListNode(int x):_value(x),_next(NULL),_prev(NULL){}
};
void Test()
{
    SharedPtr cur(new Node(1));
    SharedPtr next(new Node(2));
    cur -> _next = next;
    next -> _prev = cur;
}

上述例子中的對象引用計(jì)數(shù)不會(huì)減為0,所以不會(huì)調(diào)用析構(gòu),會(huì)造成內(nèi)存泄漏。

實(shí)際上,在庫函數(shù)中shared_ptr內(nèi)部實(shí)現(xiàn)的時(shí)候維護(hù)的就不是一個(gè)引用計(jì)數(shù),而是兩個(gè)引用計(jì)數(shù),一個(gè)表示strong reference,也就是用shared_ptr進(jìn)行復(fù)制的時(shí)候進(jìn)行的計(jì)數(shù),一個(gè)是weak reference,也就是用weak_ptr進(jìn)行復(fù)制的時(shí)候的計(jì)數(shù)。weak_ptr本身并不會(huì)增加strong reference的值,而strong reference降低到0,對象被自動(dòng)析構(gòu),weak_ptr輔助了shared_ptr而沒有增加引用計(jì)數(shù)。因此在一個(gè)環(huán)上只要把原來的某一個(gè)shared_ptr改成weak_ptr,實(shí)質(zhì)上這個(gè)環(huán)就可以被打破了。

②模擬實(shí)現(xiàn)的SharedPtr只能用于new空間,并不能打開文件,這個(gè)時(shí)候可以用仿函數(shù)來解決這個(gè)問題。

template 
struct FClose                    
{
     void operator () (T* ptr)           //重載()運(yùn)算符,進(jìn)行文件指針的釋放。
    {
         fclose(ptr);
    }
};
template 
struct Delete
{
public :
     void operator () (T* ptr)          //重載()運(yùn)算符,進(jìn)行堆上空間的釋放
    {
         delete ptr;
    }
};
template >   //多傳一個(gè)參數(shù),默認(rèn)為Delete,即默認(rèn)它是在堆上new出空間,需要用delete釋放
class SharedPtr
{
public:
	SharedPtr(T* ptr=NULL)
		:_ptr(ptr)
		,_pcount(new int(1))
	{}
	SharedPtr( SharedPtr& t)
	{
		_ptr=t._ptr;
		_pcount=t._pcount;
		(*_pcount)++;
	}
	SharedPtr& operator=(SharedPtr& t)
	{
		if(_ptr!=t._ptr)
		{
			if(--(*_pcount)==0)
			{
				delete _ptr;
				delete _pcount;
			}
			_ptr=t._ptr;
			_pcount=t._pcount;
			++(*p_count);
		}
		return *this;
	}
	T& operator*(){	return *_ptr;	}
	T* operator->(){	return _ptr;	}
	~SharedPtr()
	{
		if(--(*_pcount)==0)
		{
			DEL()(_ptr);      //釋放空間時(shí),用DEL類型生成匿名對象調(diào)用()函數(shù)
			delete _pcount;
		}
	}
private:
	T* _ptr;
	int* _pcount;
};

當(dāng)需要給文件指針定義時(shí),只用多傳一個(gè)參數(shù)就可以達(dá)到效果。

SharedPtr> b= fopen("test.txt", "w");這樣在析構(gòu)時(shí),就會(huì)調(diào)用FClose()生成匿名對象,F(xiàn)Close()(_ptr)然后調(diào)用FClose的()運(yùn)算符重載函數(shù)。

創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開啟,新人活動(dòng)云服務(wù)器買多久送多久。


分享題目:RAII和模擬實(shí)現(xiàn)智能指針-創(chuàng)新互聯(lián)
分享路徑:http://weahome.cn/article/doidop.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部