以對象管理資源
許多資源被動態分配與heap內而後被用於單一區塊或函數內。他們應該在控制流離開那個區開或函數時被釋放。
class Investment{...}; //投資類型繼承體系中的root class
Investment* createInvestment(); //返回指針,指向Investment繼承體系內的動態分配對象,調用者有責任刪除它
void f(){
std::shared_ptr<Investment> pInv(createInvestment()); //調用factory函數
... //經由shared_ptr的析構函數自動刪除pInv
}
獲得資源後立刻放進管理對象內。以對象管理資源的觀念常被稱爲資源獲取時機便是初始化時機(Resource Acquisition Is Initialization;RAII)
管理對象運用析構函數確保資源被釋放。
然而並非所有資源都是heap-based,對那種資源而言,像auto_ptr和shared_ptr這樣的智能指針往往不適合作爲資源管理者。
假如我們使用C API函數處理類型爲Mutex的互斥對象,共有lock和unlock兩函數可有:
void lock(Mutex* pm); //鎖定pm所指互斥器
void unlock(Mutex* pm); //將互斥器解除鎖定
建立一個class用來管理機鎖,這樣的class基本結構由RAII守則支配,也就是”資源在構造期間獲得,在析構期間釋放”:
class Lock{
public:
explicit Lock(Mutex* pm):mutexPtr(pm)
{lock(pm);} //獲得資源
~Lock(){unlock(mutexPtr);} //釋放資源
private:
Mutex* mutexPtr;
};
客戶對Lock的用法符合RAII方式:
Mutex m; //定義你需要的互斥器
...
{ //建立一個區塊定義critical section
Lock m1(&m); //鎖定互斥器
... //執行critical section內的操作
} //在區塊末尾,自動解除互斥器鎖定
Lock ml1(&m); //鎖定m
Lock ml2(ml1); //將ml1複製到ml2身上,會發生什麼?
面對“一個RAII對象被複制會發生什麼?”大多數時候會有兩種選擇:
1)禁止複製
class Uncopyable{
protected: //允許derived對象構造和析構
Uncopyable(){}
~Uncopyable(){}
private: //不予實現
Uncopyable(const Uncopyable&); //阻止copying
Uncopyable& operator=(const Uncopyable&);
};
class Lock:private Uncopyable{
public:
... //如前
}
2)對底層資源基礎“引用計數法”
tr1::shared_ptr允許指定所謂的“刪除器”,那是一個函數或函數對象,當引用次數爲0時便被調用。
class Lock{
public:
explicit Lock(Mutex* pm)
: mutexPtr(pm,unlock) //以unlock函數作爲刪除器
{
lock(mutexPtr.get());
}
private:
std::tr1::shared_ptr<Mutex>mutexPtr;
};