第三章資源管理
條款13:以對象管理資源
RAAI(Resource Acquisition IsInitialization: RAII) 資源取得時機便是初始化時機
n 為防止資源泄漏,請使用RAII對象,它們在建構函式中獲得資源並在解構函式中釋放資源
n 兩個常被使用的RAIIclasses分別是tr1::shared_ptr和auto_ptr。前者通常是較佳選擇,因為其copy行為比較直觀。若選擇auto_ptr,複製動作會使它(被複製物)指向null。
auto_ptr:
auto_ptr在構造時擷取對某個對象的所有權,在析構時釋放該對象。其解構函式自動對其所指對象調用delete
int*p = new int(0);
auto_ptr<int>ap(p);
auto_ptr<nt> ap(new int(0)); //獲得資源後立刻放進管理對象RAAI
從此我們不必關心何時釋放p,也不用擔心發生異常會有記憶體流失。
要記住幾點:
1. auto_ptr析構的時候肯定會刪除他所擁有的那個對象,所以兩個auto_ptr不能同時擁有同一個對象。為了預防這個問題,auto_ptr有個性質:若通過copy建構函式或copy assignment操作符複製它們,它們會變成null,而複製所得的指標將取得資源的唯一擁有權。
2. auto_ptr的解構函式中刪除指標用的是delete,而不是delete[],所以我們不該用auto_ptr來管理一個數組指標。
shared_ptr: 一種“已用計數型智慧指標(RCSP Reference-counting smart pointer)”
RCSP持續追蹤共有多少對象指向某筆資源,並在無人指向它時自動刪除該資源。但它無法打破環狀引用,例如兩個其實已經沒被使用的對象彼此互指,因而好像還處在“被使用”狀態。
條款14:在資源管理類中小心copying行為
n 複製RAII對象必須一併複製它所管理的資源,所以資源的copying行為決定RAII對象的copying行為
n 普通而常見的RAII classcopying行為是:抑制copying 、施行引用計數法。
tr1::shared_ptr允許指定所謂的“刪除器”
條款15:在資源管理類中提供對原始資源的訪問
n APIs往往要求訪問原始資源,所以每一個RAII class應該提供一個“取得其所管理之資源”的辦法
n 對原始資源的訪問可能經由顯示轉換或隱式轉換。一般而言顯式轉換比較安全,但隱式轉換對客戶比較方便。
條款16:成對使用new和delete時要採取相同形式
n 如果你在new運算式中使用[],必須在相應的delete運算式中也使用[]。如果你在new運算式中不使用[],一定不要在相應的delete運算式中使用[]
條款17:以獨立語句將newed對象置入智能指標
n 以獨立語句將newed對象置入智能指標內。如果不這樣做,一旦異常被拋出,有可能導致難以察覺的資源泄漏。
例如
int priority();
voidprocessWidged(std::tr1::shared_ptr<Widget> pw, int priority);
考慮調用
processWidged(std::tr1::shared_ptr<Widget>(newWidget), priority())
可能會產生這樣的執行順序:
1. 執行new Widget
2. 調用priority
3. 調用tr1::shared_ptr建構函式
如果priority的調用導致異常,new Widget返回的指標將會遺失,所以應該採用以下的調用方法:
std::tr1::shared_ptr<Widget> pw(newWidget);
processWidget(pw, priority());