天天看點

effective c++條款13

所謂資源就是,一旦用了它,将來必須還給系統

c++最常使用的資源就是動态配置設定記憶體,但記憶體隻是你必須管理的衆多資源之一,其他常見的資源還包括檔案描述器,互鎖器,圖形界面中的畫筆,畫刷,字型,資料庫連接配接,網絡socket等等

RAII是Resource Acquisition Is Initialization的簡稱,是C++語言的一種管理資源、避免洩漏的慣用法。利用的就是C++構造的對象最終會被銷毀的原則。RAII的做法是使用一個對象,在其構造時擷取對應的資源,在對象生命期内控制對資源的通路,使之始終保持有效,最後在對象析構的時候,釋放構造時擷取的資源

現在進入正文:

1.為防止資源洩露,請使用RAII對象,他們在構造函數中獲得資源,在析構函數中釋放資源

2.兩個常使用RAII對象類是shared_ptr和auto_ptr,前者通常是較佳選擇,其copy行為比較直覺(複制後,兩個RAII對象指向的是同一個資源),auto_ptr複制後,會發生所有權的轉讓(複制動作,會使前一個RAII對象指向NULL)

假設有這樣的類

class People
{
    friend ostream& operator<<(ostream& out, const People& p)
    {
        out << p.m_name << " " << p.m_age;
        return out;
    }
public:
    People(string name, int age) :m_name(name), m_age(age){}
    ~People(){ cout << "執行People對象的析構函數" << endl; }
    People(const People& rhs) :m_name(rhs.m_name), m_age(rhs.m_age){}
    People& operator=(const People& rhs)
    {
        if (this == &rhs)
            return *this;
        this->m_name = rhs.m_name;
        this->m_age = rhs.m_age;
        return *this;
    }
private:
    string m_name;
    int m_age;
};
           

一個人出生就注定了死亡,是以,我們可以寫這樣一個函數

void f()
{
    People* pl=new People("XXX",);
    ...
    delete People;
}
           

這裡就可能存在問題,可能在delete之前就有return,goto語句,或者delete之前的語句抛出異常,這樣就沒有可能去執行delete語句了,總而言之,由于各種可能的原因,這個函數不是很可靠

為確定heap上配置設定的People對象的資源總是被釋放,我們需要将它放進另一個管理類對象中,當控制流離開People對象的塊區域中,該管理對象的析構函數會自動釋放

代碼如下

#include<windows.h>
#include <iostream>
#include <memory>
#include <string>
using namespace std;

int main()
{
    {
        auto_ptr<People>m_ptr1(new People("dyy", ));
        cout << *m_ptr1 << endl;
        auto_ptr<People>m_ptr2 = m_ptr1;
        if (m_ptr1.get() == NULL)
        {
            cout << "指針為空" << endl;
        }
    }
    system("pause");
    return ;
}
           

這段代碼運作結果:

執行People對象的析構函數

當然auto_ptr的複制特性比較特殊,發生複制時,前一個auto_ptr會失去對象資源

還有shared_ptr可以使用,它的複制特性就比較正常,采用引用計數,複制之後,多個shared_ptr指向同一個對象資源

另外沒有針對C++動态配置設定數組而設計的auto_ptr和shared_ptr(auto_ptr和shared_ptr采用的是delete,而不是delete[]),boost苦中有對應該需求的指針

繼續閱讀