終於要開始第三章了~ 第三章總共有5個守則,馬上就來看看第一則吧!
第一個守則是:
Use obejcts to manage resources
假設現在我們想要創建一個物件,並在使用完畢後把他刪除,我們可能會這樣寫:
void f()
{
Investment *pInv = createInvestment();
...
delete pInv;
}
這種寫法有一些潛在危險性,讓這個資源沒有被完全delete掉。例如:在...裡面有先return
了,不是每次都可以返回;或者是中途會報exception
,一樣執行不到最後;又或者delete
是寫在loop裡面,在執行到之前有goto
或continue
把它跳掉......。雖然在寫的當下,你可能考慮到全部的情況,可以避免以上的所有情形,然而,久了之後你不能確定未來的你或其他人會不會忽略了這些考量,而動到了原本的設計,導致以上狀況有可能發生,若只靠原本的這個function設計並不可靠。
那要確保createInvestment()
產生的東西都可以被刪除,可以怎麼做呢?我們可以把它放到一個物件裡,並把刪除它的操作放到它的destructor,這樣就可以確保離開f()
的時候它會被自動刪除。而auto_ptr
就是為此情形量身打造的,它屬於一種smart pointer,destructor會自動對它指向的東西call delete
。它的用法如下:
void f()
{
std::auto_ptr<Investment> pInv(createInvestment());
...
}
這個用法顯示了兩個使用物件來控制resource的重點:
createInvestment
創出來的資源馬上用來初始化auto_ptr
並由它來管理,這個用物件來管理資源的方式又稱為RAII─Resource Acquisition Is Initialization ,因為時常會在同一個statement裡面同時取得資源並把這個資源拿來初始化resource-managing object;有時候可能不是初始化,而是assign的操作,但總之就是取得後轉移到resource-managing object上。也由於auto_ptr會自動delete
的特性,我們不能讓多個auto_ptr
指向同一個物件,否則物件就會被重複刪除;因而auto_ptr
有個特別行為就是copy它的時候(那兩個copying functions),就會把它指向的東西設為null
,以保證只有一個人指向它。
這邊不就多再說明auto_ptr
什麼時候會被設成null的行為了,因為auto_ptr
已經被C++11放棄了~~就因為它上面的這些比較難以掌控的行為,C++11後就有了unique_ptr
。差別在哪裡呢?可以參考下面的一些參考資料。這邊簡單來說就是:當你物件被unique_ptr
指之後,它就不能再被copy,auto_ptr
不會報錯,unique_ptr
會。顧名思義,用unique_ptr
來指向的物件,它就是"unique"的,不期望它還被別人使用;如果別人也會指向它,那就請改用下面會提到的─shared_ptr。
除了auto_ptr
,還有RCSP- Reference-counting smart pointer型的smart pointer。它會記錄這個物件被指向多少次,而只有在所有指向它的物件都被destroyed掉後才去delete這個物件。shared_ptr
就是這種應用。你可以這樣寫(書中原本的寫法shared_ptr
還在TR1中,但C++11後已納入標準函式庫,因此下方寫沒有TR1的版本)
void f()
{
std::shared_ptr<Investment> pInv(createInvestment());
}
使用它,就可以正常的call copy functions沒有問題,例如這樣:
void f()
{
std::shared_ptr<Investment> pInv1(createInvestment());
std::shared_ptr<Investment> pInv2(pInv1);
pInv1 = pInv2;
}
而對於dynamically allocated array,就沒有這種smart pointer的應用(就是如果你指向的是一個array,smart pointer在delete的時候並不是delete[]
!!!)。但通常其實沒有需要,大部分可用vector
與string
來取代。
總之這個守則想表達的就是:如果在destructor以外去手動delete,你可能在錯誤的道路上。有時候可能不一定能用smart pointer來達成,但你可以自行創建一個類似的object。當然這也有其他要注意的事項,後面的守則會再提到。
貼心重點提醒:
- To prevent resource leaks, use RAII obejcts that acquire resources in their constructors and release them in their destructors.
- Two commonly useful RAII classes are
shared_ptr
andauto_ptr
.shared_ptr
is usually the better choice, because its behavior when copied is intuitive. Copying anauto_ptr
sets it to null.
注意:第二點改用unique_ptr
。