當(dāng)我們?cè)诔绦蛑蟹峙滟Y源時(shí),一定要確保這個(gè)資源在應(yīng)該被釋放的時(shí)候能夠正確地釋放。查看以下代碼:
class Investment{...}
void f(){
Investment* p = createInvestment(); //createInvestment()是一個(gè)返回Investment對(duì)象指針的工廠方法
...
delete p;
實(shí)際上,delete操作很有可能不會(huì)被執(zhí)行,比如在delete之前有一個(gè)過(guò)早的return操作,類似的情況是在一個(gè)循環(huán)中早于delete的continue被調(diào)用而跳出循環(huán)導(dǎo)致的delete沒(méi)有被調(diào)用。
雖然你可以謹(jǐn)慎地寫(xiě)代碼,保證delete操作能被執(zhí)行,但是當(dāng)這段代碼交由他人維護(hù)的時(shí)候,可能會(huì)導(dǎo)致以上的情況(比如添加了return),所以依靠“程序會(huì)執(zhí)行到這一步”這個(gè)思想是行不通的。
大家都知道,一個(gè)局部資源在離開(kāi)其作用域時(shí)會(huì)被自動(dòng)釋放,那么如果將資源放進(jìn)對(duì)象中,然后離開(kāi)作用域時(shí),對(duì)象的析構(gòu)函數(shù)就能自動(dòng)釋放資源。這就是auto_ptr的思想。
void f(){
std::auto_ptr<Investment> p(createInvestment());
...
}
auto_ptr是一個(gè)模板(可以像指針一樣使用),可以將指針?lè)胚M(jìn)特例化后的auto_ptr中,這樣當(dāng)auto_ptr離開(kāi)作用域時(shí),就能夠自動(dòng)析構(gòu),也就保證了資源的正確釋放。
但是有個(gè)需要注意的地方,auto_ptr被銷(xiāo)毀時(shí)會(huì)自動(dòng)刪除它所指向的資源,所以不要讓多個(gè)auto_ptr指向同一個(gè)對(duì)象,因?yàn)橐粋€(gè)對(duì)象絕對(duì)不能被刪除一次以上!,所以auto_ptr有一個(gè)獨(dú)特的性質(zhì),當(dāng)你用復(fù)制構(gòu)造函數(shù)或者operator=操作它們時(shí),它們會(huì)變成null,而復(fù)制所得的指針會(huì)取得資源的所有權(quán)(就像轉(zhuǎn)移所有權(quán)一樣)。
還有一種智能指針:shared_ptr,這種智能指針的機(jī)制可以讓多個(gè)shared_ptr指向同一個(gè)對(duì)象,它的機(jī)制依賴于“引用計(jì)數(shù)”的概念,當(dāng)shared_ptr對(duì)象被析構(gòu)時(shí),引用計(jì)數(shù)減一,析構(gòu)時(shí)檢查引用計(jì)數(shù),當(dāng)引用計(jì)數(shù)變?yōu)?時(shí)這個(gè)對(duì)象內(nèi)所含的資源會(huì)被釋放。
有一個(gè)值得一提的事實(shí),auto_ptr和shared_ptr在其析構(gòu)函數(shù)內(nèi)做的操作都是delete而不是delete[],這意味著這兩種智能指針不能存儲(chǔ)動(dòng)態(tài)分配來(lái)的數(shù)組(因?yàn)椴荒鼙蝗酷尫牛侨绻氵@么操作,編譯器并不會(huì)報(bào)錯(cuò)!其實(shí)string和vector已經(jīng)總是可以取代動(dòng)態(tài)分配得來(lái)的數(shù)組,所以我在這里的理解是,這樣設(shè)計(jì)的原因促使你使用更方便的vector和string,而不是使用C風(fēng)格的字符串或者動(dòng)態(tài)數(shù)組。如果你執(zhí)意要使用動(dòng)態(tài)數(shù)組的話,可以考慮以下boost::scoped_array和boost::shared_array。
最后,我們還要確保存儲(chǔ)在智能指針內(nèi)的資源是已經(jīng)初始化的,這個(gè)問(wèn)題會(huì)在條款18被提到。