天天看點

條款 13:以對象管理資源

條款 13:以對象管理資源

Use objects to manage resources
  1. 所謂資源就是,一旦用它,将來必須還你給系統。
  2. 單純依靠函數進行資源釋放行不通
//假設我們的程式庫各類繼承一個root類
class Investment{...};//投資類型,繼承體系中的root class
//假設我們通過工廠産生對象
Investment* creatInvestment();//多态指針
//這是一個動态對象,調用者有責任 釋放他
//假設用f()函數履行這個責任
void f(){
	Investment* pInv=creatInvestment();//調用工廠函數
	...//doSomething
	delete pInv;//釋放對象
}
//這麼寫看起來妥當。但是有些情況下可能無法成功釋放
//例如,doSomething提前出現一個return,而導緻函數提前退出
//例如,doSomething時抛出一些異常,導緻無法執行到delete語句
//無論是什麼原因,delete被忽略會導緻記憶體洩漏
//完美的語序自然可以避免該問題,但是換來的确實維護的代價
//是以單純依靠函數進行資源釋放行不通

           
  1. 把資源放進對象内,我們便可以依靠C++的析構函數 自動調用機制確定資源被釋放。
  2. “以對象管理資源”的關鍵想法:1.獲得資源後立即放進管理對象内。2.管理對象利用析構函數確定資源被釋放
  3. 關于auto_ptr的一些知識:
//auto_ptr是類指針對象,也就是所謂的智能指針,
//其析構函數自動對其所指向的對象調用delete
//下面示範使用auto_ptr避免記憶體洩漏的可能性
void f(){
	//一如既往的調用工廠函數,使用pInv
	std::auto_ptr<Investment> pIvn(creatInvestment());
	...
	//經由auto_ptr的析構函數自動删除pIvn
}
//該例子給出了兩個“以對象管理資源”的關鍵想法
//1.獲得資源後立即放進管理對象内。
//2.管理對象利用析構函數確定資源被釋放
//由于auto_ptr被銷毀時會自動釋放其所指之物,
//是以注意不要讓多個auto_ptr指向一個對象,否則會導緻
//同一對象的多次釋放(釋放不存在的資源),進而出錯
//為了預防該問題,auto_ptr有一個性質:
//若通過複制構造函數,或複制複制操作符複制他們,
//他們會變成null,而複制所得指針将取得資源的唯一擁有權。

void f(){
	//pTnv1指向creatInvestment的傳回物
	std::auto_ptr<Investment> pInv1(creatInvestment());
	atd::auto_ptr<Investment> pInv2(pInv1);//現在pInv2指向對象
									//pInv1變為null
	pInv1=pInv2;//現在pInv1指向對象
			//pInv2變為nul
}
//通過上述例子可以看到我們描述的例子
//而且可以看到,auto_ptr限制了指針正常的複制行為。
//是以auto_ptr也不是一個管理資源的萬能利器

//auto_ptr的替代方案是“引用計數型智慧指針”(RCSP)
//所謂的RCSP也是一個智能指針,持續追蹤共有多個對象指向某筆資源
//并在無人指向他們時自動删除該資源
//RCSP的行為類似垃圾回收機制
//但是RSCP不能打破“環狀引用”,
//例如兩個其實已經沒有被使用的對象彼此互指,因而好像還在被使用狀态

//TR1的tr1::shared_ptr就是個RCSP
void f(){
	//一如既往的調用工廠函數,使用pInv
	std::tr1::shared_ptr<Investment> pIvn(creatInvestment());
	...
	//經由shared_ptr的析構函數自動删除pIvn
}
//該代碼看起來與上一個例子相似,但是卻比它正常得多
void f(){
	//pTnv1指向creatInvestment的傳回物
	std::tr1::shared_ptr<Investment> pInv1(creatInvestment());
	atd::tr1::shared_ptr<Investment> pInv2(pInv1);//現在pInv2指向對象
									//pInv1也指向該對象
	pInv1=pInv2;//同上,無變化。
	...//當pInv1,pInv2均被銷毀,其所指的對象也被銷毀
}
//還有一點應當注意的是上述的兩種智能指針
//在其析構函數内調用delete而不是delete []動作(條款16說明),
//是以在動态配置設定的array身上使用智能指針不是一個好主意
           

請記住

1. 為防止資源洩漏,請使用資源管理對象,他們在構造函數中獲得資源并在析構函數中釋放資源.

2. 兩個常被使用的資源管理對象是tr1::shared_ptr和auto_ptr.前者通常是較佳選擇,因為其copy行為比較直覺。若選擇auto_ptr,複制動作會使他(被複制物)指向null.

繼續閱讀