今天看了下effective c++的條款13:以物件管理資源,感覺十分有理,特此做一下筆記。
假設我們使用乙個用來描述投資行為的程式庫,其中各式各樣的投資型別都繼承自乙個根類 investment:
//投資型別繼承體系中的root class
class investment;
這裡呢,我們進一步假設這個程式庫通過乙個函式為我們提供investment物件:
investment* createinvestment();//指向動態分配物件,這裡為了簡化,我就不 //寫引數了
如上所示,createinvestment函式的呼叫端使用了函式返回的物件後,就有責任刪除這個物件。假設,有個函式f()執行這個刪除操作:
void f()
這個語句看起來感覺很合理,但是,假如我省略的**細節裡有個return語句,如此一來,我的f()函式在執行了return後就不會觸及delete語句,也就不能釋放那塊記憶體。
所以,為了確保createinvestment()函式返回的資源總是能被釋放,我們需要將資源放到物件內,當控制流離開函式f後,該物件的析構函式就會自動釋放那些資源。這種做法就是本節內所討論的問題:把資源放進物件內,依靠「c++析構函式自動呼叫機制」來確保資源被釋放。
許多資源被動態分配於堆區(heap segment)內,而後就在某個函式或者區塊內被使用。這些資源需要在函式呼叫完成或者離開區塊的時候被釋放。針對這個問題,c++標準程式庫為我們提供了一些解決辦法,比如auto_ptr(俗稱智慧型指標)。auto_ptr是乙個棧物件,他的析構函式自動對其物件呼叫delete函式,達到乙個釋放資源的作用。下面介紹一下auto_ptr避免f()函式內記憶體洩漏問題:
void f()
於是,這乙個簡單的小例子就闡明了「以物件管理資源」的兩個關鍵的想法:
獲得資源後立刻放進管理物件內。
上述**中, createinvestment()函式的返回值直接作為了auto_ptr的物件的初值。實際上,這在c++裡面有個形象的說法,就是raii(resource acquisition is initialization,資源獲取即初始化)。
管理物件運用析構函式確保資源被釋放。簡而言之:只要物件離開作用域(比如離開函式的大括號)就自動呼叫析構函式,也就釋放了資源(當然如果釋放過程中出現了異常,就是比較麻煩的問題了,這一點放在後面去討論,這裡只關心資源釋放的主要功能)。
特別注意的是,由於auto_ptr被銷毀的時候回自動釋放他所指向的那塊記憶體,所以一定不能讓多個auto_ptr同時指向同乙個物件。否則,就會發生未定義的行為。為了預防這種問題,請大家像我一樣遵循如下的規則:
如果通過拷貝建構函式或者析構函式複製auto_ptr,他們就會變成null,而複製所得的指標將得到資源的唯一所有權。
這乙個規則我在這裡用**給大家進行一下簡單的演示:
std:
:auto_ptrpinv(createinvestment());
std:
:auto_ptrpinv2(pinv);//情況1:呼叫拷貝建構函式
pinv1 = pinv2;//情況2:呼叫賦值函式
如上所示,情況1和2下都會產生同乙個問題,pinv1和 pinv2都會變成null。
所以,為了解決這種詭異的現象,c++為我們提供了乙個替代方案,也就是所謂的「引用計數型智慧型指標」(rcsp,下面我都用這個詞來簡寫)。tr1的shared_ptr就是常用的rcsp。
void f()
這樣的寫法看似與auto_ptr類似,但是實際上,使用shared_ptr不會出現前面所說的那種置null現象,如下**就可以看出差別:
void f()
當然,除了以上的一些特點,還需要注意的是,auto_ptr與tr1::shared_ptr在析構函式內呼叫的都是delete,而不是delete,所以,請注意:動態分配陣列的時候,請勿使用auto_ptr與tr1::shared_ptr(儘管編譯器不會報錯,如果你非要用含有諸如auto_ptr與tr1::shared_ptr的類,那麼請你去學一下boost)。
小節:為了防止記憶體洩漏,請務必使用raii物件。他們會在建構函式中獲取資源,在析構函式中delete資源。
常用的raii物件是std::auto_ptr和std::tr1::shared_ptr,後面這個是較佳的選擇。還有就是注意二者在呼叫拷貝建構函式和賦值函式時的區別。
條款13 以物件管理資源
問題 解決 智慧型指標。把資源放入物件內,利用析構函式確保釋放。1 資源取得時機便是初始化時機 resource acquisition is initialization raii 2 管理物件運用析構函式確保資源被釋放。別讓auto ptr同時指向同一物件。為了預防這個問題,能過copy建構函式...
條款13 以物件管理資源
我們都知道,當new乙個東西之後,必須delete它。但是問題可能出現在在new和delete之間 比如中間出現了異常,或者return之類的。一種比較好的作法是通過物件來管理 因為當物件的宣告週期結束以後,會呼叫析構函式,而在析構函式中delete,這樣的作法就靠譜多了。在標準c 中,定義了2種管...
條款13 以物件管理資源
一 如下 假設各種子型別繼承 root class investmen class investment investment createinevstment factory函式 void f 在 區域內乙個過早return,或者期間丟擲異常,流程控制不可能經過這條語句,所以這樣的話就會導致資源洩...