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

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

智能指針和異常

今天讓我們來(lái)分析一下C++中的智能指針和異常,首先呢先普及一下概念!

創(chuàng)新互聯(lián)企業(yè)建站,十余年網(wǎng)站建設(shè)經(jīng)驗(yàn),專注于網(wǎng)站建設(shè)技術(shù),精于網(wǎng)頁(yè)設(shè)計(jì),有多年建站和網(wǎng)站代運(yùn)營(yíng)經(jīng)驗(yàn),設(shè)計(jì)師為客戶打造網(wǎng)絡(luò)企業(yè)風(fēng)格,提供周到的建站售前咨詢和貼心的售后服務(wù)。對(duì)于網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)中不同領(lǐng)域進(jìn)行深入了解和探索,創(chuàng)新互聯(lián)在網(wǎng)站建設(shè)中充分了解客戶行業(yè)的需求,以靈動(dòng)的思維在網(wǎng)頁(yè)中充分展現(xiàn),通過(guò)對(duì)客戶行業(yè)精準(zhǔn)市場(chǎng)調(diào)研,為客戶提供的解決方案。

(1)智能指針:智能或者自動(dòng)化的管理指針?biāo)鶗?huì)向的動(dòng)態(tài)資源的釋放。

(2)異常:當(dāng)一個(gè)函數(shù)發(fā)現(xiàn)自己無(wú)法處理的錯(cuò)誤時(shí),讓函數(shù)的調(diào)用者直接或間接的處理這個(gè)問(wèn)題。

(3)RAII:資源分配即初始化。構(gòu)造函數(shù)完成對(duì)象的初始化,析構(gòu)函數(shù)完成對(duì)象的清理,而不是刪除。

在實(shí)際寫(xiě)代碼過(guò)程中,我們很容易寫(xiě)出存在異常的代碼,不信來(lái)看看下面幾個(gè)例子 :

void Test()
{
	int *p = new int(1);
	if (1)
	{
		return;
	}
	delete p;
}

很容易可以看出在if語(yǔ)句中已經(jīng)返回了,那后面的代碼自然是執(zhí)行不了了,所以就出現(xiàn)了內(nèi)存泄露的危險(xiǎn),這可是非??膳碌哪?,它可能會(huì)耗盡內(nèi)存,不僅當(dāng)前程序會(huì)崩潰,嚴(yán)重的整個(gè)系統(tǒng)都會(huì)崩潰,這是看你怎么辦,哈哈。這時(shí)肯定會(huì)有人想到了C++里面不是有異常捕獲嗎?是的,為了增加代碼的兼容性,C++采用了下面的代碼來(lái)捕獲異常:

throw 拋出異常;
try
{
	//可能發(fā)生異常的代碼
}
catch (異常類型)
{
	//發(fā)生異常后的處理方法
}

上面的代碼進(jìn)行這樣處理不就沒(méi)事了嗎?

void Test()
{
	int *p = new int(1);
	try
	{
		if (1)
		{
			throw 1;
		}
	}
	catch (int e)
	{
		delete p;
		throw;
	}
	delete p;
}

但是這里在catch中卻二次拋出異常,這樣管理起來(lái)非常混亂。所以就引入了智能指針,用它來(lái)解決異常更方便。上面提到的RAII就是編寫(xiě)異常安全代碼的關(guān)鍵思想。

下來(lái)介紹一下Boost庫(kù)里的智能指針吧。

智能指針和異常

下面給出這些智能指針的模擬實(shí)現(xiàn)接口,具體的實(shí)現(xiàn)自己完成嘍

(1)AutoPtr有兩種實(shí)現(xiàn)方法

//現(xiàn)代寫(xiě)法
template 
class AutoPtr
{
public:
	AutoPtr(T* ptr);
	AutoPtr(AutoPtr& ap);
	AutoPtr& operator=(AutoPtr& ap);
	T& operator*();
	T* operator->();
	~AutoPtr();
protected:
	T* _ptr;
};
//舊方法
template
class AutoPtr
{
public:
	AutoPtr(T* ptr);
	AutoPtr(AutoPtr& ap);
	AutoPtr& operator=(AutoPtr& ap);
	T& operator*();
	T* operator->();
	~AutoPtr();
protected:
	T* _ptr;
	bool _owner;
};

很容易可以看出舊寫(xiě)法里多了一個(gè)布爾類型的成員變量,大家都知道AutoPtr采用的是管理權(quán)轉(zhuǎn)移的方式來(lái)管理的。所以誰(shuí)是資源的管理者,誰(shuí)的_owner值就為true,其他的對(duì)象的_owner自然就是false。在現(xiàn)代寫(xiě)法中去除了這種方式,直接采用對(duì)象賦空的方式,看起來(lái)還是舊的寫(xiě)法似乎更為合理一點(diǎn),但是新事物的出現(xiàn)肯定有它存在的理由,下來(lái)我們看個(gè)例子:

AutoPtr ap1(new int(1));
if (某個(gè)條件)
{
	AutoPtr ap2(ap1);
}

大家想到了嗎?對(duì)于舊寫(xiě)法,如果進(jìn)入if語(yǔ)句,創(chuàng)建ap2后進(jìn)行拷貝ap1._owner=false,ap2._owner=true;但是出了if代碼塊,就出了ap2的作用域,ap2被釋放,但ap1里還保存著原來(lái)的地址,所以可能發(fā)生二次釋放或訪問(wèn)問(wèn)題,但這個(gè)時(shí)候ap1就是野指針啦,后果很嚴(yán)重呢!

但對(duì)于現(xiàn)代寫(xiě)法,拷貝后將ap1賦空,想要再用ap1時(shí)進(jìn)行檢測(cè)為空,那也就避免使用它啦。

(2)ScopedPtr

template
class ScopedPtr
{
public:
	ScopedPtr(T* ptr);
	~ScopedPtr();
	T& operator*();
	T* operator->();
protected:
	ScopedPtr(ScopedPtr& sp);
	ScopedPtr& operator=(ScopedPtr& sp);
protected:
	T* _ptr;
};

容易看出它里面直接把拷貝構(gòu)造函數(shù)和重載賦值函數(shù)聲明為了保護(hù)或者私有的,在類外是不能被調(diào)用的,也就起到了防拷貝的作用。

(3)SharedPtr

template
class SharedPtr
{
public:
	SharedPtr(T* ptr);
	SharedPtr(const SharedPtr& sp);
	~SharedPtr();
	SharedPtr& operator=(const SharedPtr& sp);
	T& operator*();
	T* operator->();
public:
	void UseCount();
	void GetPtr();
protected:
	void _Release();
protected:
	T* _ptr;
	long* _pCount;
};

(4)ScopedArray/SharedArray

template
class ScopedArray
{
public:
	ScopedArray(T* ptr);
	~ScopedArray();
	T& operator[](size_t index);
protected:
	ScopedArray(const ScopedArray& sp);
	ScopedArray& operator=(const ScopedArray& sp);
protected:
	T* _ptr;
};

//
template
class SharedArray
{
public:
	SharedArray(T* ptr);
	~SharedArray();
	SharedArray(const SharedArray& sp);
	SharedArray& operator=(const SharedArray& sp);
	T& operator[](size_t index);
protected:
	void _Release();
protected:
	T* _ptr;
	long* _pCount;
};

這些當(dāng)中SharedPtr是使用最廣泛的,但在上面SharedPtr的實(shí)現(xiàn)方法中還存在幾個(gè)重要的問(wèn)題:

1,引用計(jì)數(shù)器更新存在著線程安全

對(duì)于這個(gè)問(wèn)題呢,我還沒(méi)有能力去解決,待我學(xué)成歸來(lái),一定收拾它。

2,循環(huán)引用

我們用一個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明一下什么是循環(huán)引用

#include
struct Node//定義一個(gè)雙向鏈表
{
	shared_ptr _next;
	shared_ptr _prev;
	~Node()
	{
		cout << "delete" << this << endl;
	}
};
void TestSharedPtr()
{
	shared_ptr cur(new Node());
	shared_ptr next(new Node())
	cur->_next = next;
	next->_prev = cur;

}

運(yùn)行這段代碼你會(huì)發(fā)現(xiàn),咦,為什么沒(méi)有輸出呢?也就是說(shuō)cur和next根本沒(méi)用被釋放。大家看下面的圖

智能指針和異常

在用SharedPtr實(shí)現(xiàn)雙向鏈表時(shí),會(huì)發(fā)生循環(huán)引用,這是一個(gè)很特殊的場(chǎng)景。

因?yàn)閏ur->_next和next->_prev相互依賴,所以在出了作用域以后都等著對(duì)方釋放,處于一種僵持狀態(tài)。因而沒(méi)用調(diào)用析構(gòu)函數(shù)。

解決方法是采用weak_ptr弱指針,如下:

#include
struct Node//定義一個(gè)雙向鏈表
{
	weak_ptr _next;
	weak_ptr _prev;
	~Node()
	{
		cout << "delete" << this << endl;
	}
};

weak_ptr在創(chuàng)建對(duì)象時(shí)引用計(jì)數(shù)為1,而在cur->_next=next和next->_prev=cur中對(duì)cur和next的引用計(jì)數(shù)不加1,這就很好的解決了循環(huán)引用的問(wèn)題。

3,定置刪除器

先介紹一個(gè)概念仿函數(shù),顧名思義它類似于函數(shù)但并不是函數(shù),而是一個(gè)類。只不過(guò)在類的對(duì)象調(diào)用成員函數(shù)的時(shí)候特別像是函數(shù)的調(diào)用,也就是在 這個(gè)類中重載了operator()。看兩個(gè)小例子:

(1)

void TestSharedPtr()
{
	int *p1 = (int *)malloc(sizeof(int)* 10);
	shared_ptr sp1(p1);
}

程序看上去沒(méi)有問(wèn)題,可能也沒(méi)有崩潰,可是malloc和free要成對(duì)使用,這里存在內(nèi)存泄露的問(wèn)題。

(2)

void TestSharedPtr()
{
	FILE* p2 = fopen("test.cpp", "r");
	shared_ptr sp2(p2,Fclose());//出作用域釋放文件,發(fā)生崩潰
}

當(dāng)shared_ptr對(duì)象是文件時(shí),出作用域釋放,系統(tǒng)自然會(huì)崩潰。

怎么解決上面的問(wèn)題的?

struct Free
{
	void operator()(void* ptr)
	{
		cout << "Free:" << ptr << endl;
		free(ptr);
	}
};
struct Fclose
{
	void operator()(void* ptr)
	{
		cout << "Fclose" << ptr << endl;
		fclose((FILE*)ptr);
	}
};
void TestSharedPtr()
{
	int *p1 = (int *)malloc(sizeof(int)* 10);
	shared_ptr sp1(p1,Free());
	Fclose f;
	FILE* p2 = fopen("test.cpp", "r");
	shared_ptr sp2(p2,Fclose());
}

這就是一個(gè)仿函數(shù)的使用實(shí)例。

那接下來(lái)就用它來(lái)模擬實(shí)現(xiàn)shared_ptr的定置刪除器吧,同樣還是給出接口。

template
struct DefaultDel
{
	void operator()(T* ptr)
	{
		delete ptr;
	}
};
template
struct Free
{
	void operator()(T* ptr)
	{
		free(ptr);
	}
};
template>
class SharedPtr
{
public:
	SharedPtr(T* ptr);
	SharedPtr(T* ptr,D del);
	SharedPtr(const SharedPtr& sp);
	~SharedPtr();
	SharedPtr& operator=(const SharedPtr& sp);
	T& operator*();
	T* operator->();
public:
	void UseCount();
	void GetPtr();
protected:
	void _Release();
protected:
	T* _ptr;
	long* _pCount;
	D _del;
};
void TestDeleter()
{
	SharedPtr> sp1(new int(1));
	SharedPtr> sp2((int *)malloc(sizeof(int)));
	SharedPtr sp3(new int(1));
	SharedPtr> sp4((int *)malloc(sizeof(int)));
}

好了,智能指針就說(shuō)這么多啦。小伙伴明白了嗎?


分享標(biāo)題:智能指針和異常
轉(zhuǎn)載源于:http://weahome.cn/article/gdedoo.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部