Effective C++讀書筆記----資源管理
阿新 • • 發佈:2019-01-04
C++中,我們自己申請的資源,需要我們手動的釋放。
有時候我們給了顯示釋放資源的語句,但是存在有些意外情況導致釋放語句沒能成功被執行。比如說在執行釋放語句前函式提前返回;假如釋放語句在一個迴圈內部,迴圈因為continue或者break提前結束;執行釋放語句之前程式拋異常了。
- 為了防止資源洩漏,請使用RAII物件(資源獲得即初始化),他們在建構函式中獲取資源,並在解構函式中釋放資源。
- auto_ptr防止同一個資源被多次釋放(多個物件管理同一個資源)的方式為:對複製動作做特殊處理,被複制的物件將指向NULL(資源轉移)。
- shared_ptr使用引用計數的方式來防止同一個資源被多次釋放,但是存在迴圈引用的問題(boost庫中shared_ptr是執行緒安全的)。
- 我們所說的資源不僅僅是指記憶體,還有檔案描述符、鎖、socket等。對於記憶體,將它釋放掉就是將對應的指標釋放掉,但是對於其他資源,比如檔案描述符,釋放動作是將對應的檔案描述符關閉,而鎖的釋放動作是對一個已鎖定的鎖進行解鎖。
- shared_ptr中支援指定“刪除器”,可以通過建構函式的第二個引數傳遞。auto_ptr執行的釋放動作總是刪除指標。
- shared_ptr和auto_ptr都提供了get方法,用來執行顯示轉換,也就是它會返回智慧指標內部的原始指標(的復件)。
- shared_ptr和auto_ptr都過載瞭解引用“*”操作符,他們允許隱式轉換為底層原始指標。
- 對原始資源的訪問可以通過顯示轉換或者隱式轉換。一般而言,顯示轉換會比較安全,而隱式轉換對客戶來說比較方便。
- new與delete一定要搭配使用,如果使用new的使用使用了[ ] ,在使用delete的時候也一定要使用[ ] ,否則很可能會造成記憶體洩漏。
通過new動態生成一個物件時,會做兩件事。
- 呼叫operator new函式分配記憶體
- 呼叫建構函式。(如果使用new時加了方括號[ ],也就是建立一個物件陣列,會呼叫多次建構函式)
使用delete,也會做兩件事。
- 呼叫解構函式。
- 然後釋放記憶體。(如果使用new的時候使用了[ ],在呼叫解構函式的時候也會呼叫對應次數的解構函式)
陣列的記憶體通常還包括‘陣列大小’的記錄,系統可以根據這個大小來決定呼叫建構函式和解構函式的次數。
- 儘量不要對陣列形式做typedef,有時候為了方便,將陣列形式typedef為一個簡單的型別,然後使用new,雖然new後邊沒有直接跟[ ] ,但是事實上它是相當於加了 [ ] 的。這樣在後續使用delete的時候就有可能會忘記 [ ],因為很容易以為只是建立了一個單獨的物件,而不是一個物件陣列。
- 使用單獨的語句將newed得到的物件儲存於智慧指標中。如果不這樣做,如果有異常丟擲,就可能導致難以察覺的資源洩漏。
- 對於 void processWidget (std::trl::shared_ptr pw, int priority) 這樣一個函式。我們可以以如下的方式呼叫它:
processWidget (std::trl::shared_ptr (new Widget), priority())——-priority是一個返回值為int的函式,呼叫這個函式,將它的返回值作為實參傳遞給processWidget函式。
這個函式呼叫語句會做三件事:
- 呼叫priority函式
- 執行new Widget
- 呼叫trl :: shared_ptr建構函式
但是我們並不能確定priority函式和new Widget誰先被執行,如果是priority函式先被呼叫,然後執行 new Widget在將new Widget的結果作為建構函式的引數,這樣無疑是沒有任何問題的。但是如果是執行new Widget,然後再呼叫priority函式,如果在這個函式中丟擲了異常,那麼,new Widget的結果還沒有來得及儲存到一個智慧指標中,它的返回值就會被遺失,也就引發了資源洩漏。