《Effective C++》筆記:Tips13-Tips17

Tips13:以對象管理資源

1、用對象的特性來管理資源

最經常使用的資源就是,new出來的內存,即動態分配內存,此外還有數據庫鏈接,網絡sockets等等。重要的是,一旦使用完這些資源,必須給系統。數據庫

所謂,用對象管理資源,就是利用對象銷燬時,自動調用析構函數在析構函數內釋放這些資源,從而在某種程度上達到自動釋放資源的目的數組


2、RAII對象

RAIIResource Acquisiton Is Inintialization.取得資源時便初始化,即得到資源的同時,就使用該資源初始化管理對象。網絡


PS:《Effective C++》關於智能指針的建議是關於auto_ptr,tr1::shared_ptr的,而在C++11新標準中,auto_ptr能夠由unique_ptr代替, tr1::shared_ptr可使用標準庫的std::shared_ptr中。socket


Tips14:在資源管理類中當心copying行爲

1、當RAII(可視爲資源管理類)被複制時,會發生什麼?

本質問題是,當RAII被複制時,其管理的資源該怎麼處理。ide

1.禁止複製。像是C++中的輸入輸出流,就是禁止複製。經過兩種方法能夠達到禁止複製函數

  • 拷貝函數聲明爲private,且不須要實現ui

  • C++ 11:在拷貝函數的聲明後加上「=deletespa


2.對底層使用「引用計數法」。《Effective》內使用的是tr1::shared_ptr,但如今有了更好的選擇std::shared_ptr指針


3.複製底部資源。這就須要自定義拷貝函數,達到深度拷貝的功能orm


4.轉移底部資源的擁有權。自始至終,只能有一個對象管理類。《Effective》使用的是auto_ptr,C++ 11新標準中由unique_ptr,能比auto_ptr實現更多特性


Tips15:在資源管理類中提供對原始資源的訪問

1、對原始資源的訪問的兩種方式。

在某些狀況,必須直接訪問原始資源。例如 C API 沒有class的概念


1. 顯式。RAII提供一個成員函數,返回原始資源。如shared_ptrunique_ptr,都提供get()函數,返回指向資源的原始指針

2. 隱式。爲RAII提供到原始資源的隱式轉換,即重載operator()

class Font{
public:
       ...
       operator FontHandle() const;     
private:
       FontHandle f; 
};


然而在複製Font對象時,可能就會出現問題

Font f1(getFont());
FontHandle f2 = f1;

在複製的過程當中,f1被隱式轉換成FontHandle,而後複製給f2。也許f2會複製一份副本,也許f2直接指向f1的資源。若是是後者,一旦f1銷燬,資源被釋放,f2就成爲相似空懸指針。


Tips16:成對使用newdelete時要採起相同形式

new單一對象,使用delete銷燬

new對象數組,使用delete[] 銷燬對象數組


Tips17:以獨立語句將newed對象置入智能指針。

轉換爲代碼就是

T* tPtr = new T();
shared_ptr<T> p(tPtr);

對於這樣一個函數

void processWidget(shared_ptr<Widget> pw, int priority);
int priority();

如今調用

processWidget(shared_ptr<Widget>(new Widget()), priority());

C++是不能肯定以上兩個參數的方法,是按什麼順序調用的。若是出現這樣一種狀況,先調用priority(),但調用的過程當中出現異常,這就致使智能指針沒用正確初始化。在對processWidget的調用過程當中,就出現的資源泄露。

注意這樣段代碼

Widget * tPtr = new Widget ();
processWidget(shared_ptr<Widget>(tPtr), priority());
Widget widget = *tPtr;//tPtrz指向的內存已被釋放,tPtr成爲空懸指針

對於此的建議是,既然用內置指針去初始化智能指針,那就不要使用內置指針

或者,一開始就使用智能指針,內置指針僅用做初始化(臨時對象)    

shared_ptr<Widget> pw(new T());     
processWidget(pw, priority());
相關文章
相關標籤/搜索