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",20);
    ...
    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", 27));
        cout << *m_ptr1 << endl;
        auto_ptr<People>m_ptr2 = m_ptr1;
        if (m_ptr1.get() == NULL)
        {
            cout << "指針爲空" << endl;
        }
    }
    system("pause");
    return 0;
}

這段代碼運行結果:
執行People對象的析構函數

當然auto_ptr的複製特性比較特殊,發生複製時,前一個auto_ptr會失去對象資源
還有shared_ptr可以使用,它的複製特性就比較正常,採用引用計數,複製之後,多個shared_ptr指向同一個對象資源

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章