條款13:以對象管理資源

來源:互聯網
上載者:User

所謂有資源,就是你一旦使用了它,就要記得歸還系統。如果不這樣做,就會發生資源的浪費。這裡的資源不僅僅是指記憶體,也包括:檔案描述符,互斥鎖,資料庫連接…

本條款是一個直接而易懂的基於對象的資源管理方法,建立在C++對建構函式,解構函式,copy函數的基礎上。經驗顯示,經過訓練後嚴守這些做法,可以幾乎消除資源管理的問題。下面我們就開始了~~~~~

 

首先,我們以原廠模式來說起:

假如我們使用一個用來類比投資行為的程式庫,其中各式各樣的投資類型繼承自一個root class Investment;

classInvestment{};

進一步假設,這個程式庫是通過一個工廠函數供應我們某特定的Investment對象:

Investment* createInvestment(){}//返回指標,指向Investment繼承體系內的動態指派至。調用者有責任刪除它,這裡為了簡化,不寫參數。

 

現在考慮有個f函數履行了這個責任:

voidf(){

       Investment*pInv=createInvestment();

       ...

       deletepInv;

}

這似乎看起來很美好,但是不幸的事情發生了,它發生在“…”代碼中,可能是return了,也可能是出現了異常,總之,沒有執行到delete上。我們泄露的不只是那些記憶體塊,還有那些投資對象所儲存的任何資源。

 

現在的問題是pInve和delete不在同一個對象,如果它們在同一個對象,我們完全可以依靠對象的解構函式來進行析構。因此……..

我們可以用標準庫提供的auto_ptr。這是一個類指標對象。也就是所謂的智能指標。其解構函式自動對其所指對象調用delete。

voidf(){

       std::auto_ptr<Investment>pInv(createInvestment());

       ...          

}

 

這個簡單的例子示範“以對象管理資源”的兩個關鍵想法:

l  獲得資源後,立刻放進管理對象內。

在以上代碼中,createInvestment返回的資源被當作其管理者auto_ptr的初值。實際上“以對象管理資源”的觀念常被稱為“資源擷取時機便是初始化時機”(Resource Acquisition Is Initializatioin, RAII).

l  管理對象運用解構函式確保資源被釋放。

 

由於auto_ptr被銷毀時,會自動刪除它所指之物,所以一定要注意別讓多個auto_ptr同時指向同一個對象。如果真是那樣,對象會被刪除一次以上,會造成未定義行為。為了預防這個問題,auto_ptr有一個不尋常的性質:若通過copy函數複製它們,它們會變成null,而複製所得的指標將取得資源的唯一擁有權。如下:

std::auto_ptr<Investment>pInv(createInvestment());//pInv point to a Investment obj

std::auto_ptr<Investment>pInv2(pInv);//pInv2 point to obj, pInv is null

pInv=pInv2();//pInv piont to obj, pInv2 is null

這一詭異的複製行為,複加上其底層亂條件:“受auto_ptr管理的資源必須絕對沒有一個以上的auto_ptr同時指向它”。但是在STL中,容器要求其元素髮揮“正常的”複製行為,因此這些容器不得auto_ptr。

 

Auto_ptr的一個替代方案就是“引用計數型智能指標(Reference-counting smart pointer, RCSP)”。所謂的RCSP也是一個智能指標。持續追蹤共有多少個對象指向某筆資源,並在無人指向它時,自動刪除該資源。

voidf()

{

         std::tr1::shared_ptr<Investment>pInv1(createInvestment());//pInv1 point to a Investment obj

         std::tr1::shared_ptr<Investment>pInv2(pInv1);//pInv1 and pInv2 point to the same obj;

         pInv1=pInv2;//pInv1 and pInv2 point to the same obj;

}

 

Auto_ptr 和trl::shared_ptr兩者都在其解構函式內做delete而不是delete[]動作。那意味著在動態分配而得到的array身上使用Auto_ptr 和trl::shared_ptr是個壞主意。

 

請記住:

l   為防止資源流失,請使用RAII對象,它們在建構函式中獲得資源並在解構函式中釋放資源。

l   兩個常使用的RAII classes 分別是Auto_ptr 和trl::shared_ptr。後者是一個較佳的選擇。因為其copy行為比較直觀。若選擇前者,複製動作會使它指向null。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.