C++ 關(guān)于拷貝控制和資源管理部分的筆記,并且介紹了部分C++ 智能指針的概念,然后實(shí)現(xiàn)了一個(gè)基于引用計(jì)數(shù)的智能指針。關(guān)于C++智能指針部分,后面會(huì)有專門的研究。

  • 通常,管理類外資源的類必須定義拷貝控制成員。為了定義這些成員,我們首先必須確定此對(duì)象的拷貝語義。一般來講,有兩種選擇:

    • 使類的行為看起來像一個(gè)值

      類的行為像一個(gè)值:意味著它有自己的狀態(tài)。當(dāng)我們拷貝一個(gè)像值的對(duì)象時(shí),副本和原對(duì)象是完全對(duì)立的。改變副本不會(huì)對(duì)對(duì)原對(duì)象有任何影響。反之亦然。
    • 使類的行為看起來像一個(gè)指針

      行為像指針的類則共享狀態(tài)。當(dāng)我們拷貝一個(gè)這種類的對(duì)象時(shí),副本和原對(duì)象使用相同的底層數(shù)據(jù)。改變副本也會(huì)改變?cè)瓕?duì)象,反之亦然。
  • 行為像值的類

    • 通常組合了析構(gòu)函數(shù)和構(gòu)造函數(shù)的操作。類似析構(gòu)函數(shù),賦值操作會(huì)銷毀左側(cè)運(yùn)算對(duì)象的資源。類似構(gòu)造函數(shù),賦值操作會(huì)從右側(cè)運(yùn)算對(duì)象拷貝數(shù)據(jù)。

    • 編寫賦值運(yùn)算符時(shí),有兩點(diǎn)需要注意:

      1. 如果將一個(gè)對(duì)象賦予它自身,賦值運(yùn)算符必須能正確工作2. 大多數(shù)賦值運(yùn)算符組合了析構(gòu)函數(shù)和拷貝構(gòu)造函數(shù)的工作
    • 當(dāng)編寫一個(gè)賦值運(yùn)算符時(shí),一個(gè)好的方法是先將右側(cè)運(yùn)算對(duì)象拷貝到一個(gè)局部臨時(shí)對(duì)象中,然后再銷毀左側(cè)運(yùn)算對(duì)象就是安全的了。

    • 為了提供類值的行為,對(duì)于類管理的資源,每個(gè)對(duì)象應(yīng)該都擁有一份自己的拷貝。

    • 類值拷貝賦值運(yùn)算符

  • 定義行為像指針的類

    • 引用計(jì)數(shù)

      引用計(jì)數(shù)的工作方式如下:1. 除了初始化對(duì)象之外,每個(gè)構(gòu)造函數(shù)(拷貝構(gòu)造函數(shù)除外)還要?jiǎng)?chuàng)建一個(gè)引用計(jì)數(shù),用來記錄有多少對(duì)象正在與創(chuàng)建的對(duì)象共享狀態(tài)。當(dāng)我們創(chuàng)建一個(gè)對(duì)象時(shí),只有一個(gè)對(duì)象共享狀態(tài),因此計(jì)數(shù)器初始化為1。2. 拷貝構(gòu)造函數(shù)不分配新的計(jì)數(shù)器,而是拷貝給定對(duì)象的數(shù)據(jù)成員,包括計(jì)數(shù)器??截悩?gòu)造函數(shù)遞增共享的計(jì)數(shù)器,指出給定對(duì)象的狀態(tài)又被一個(gè)新用戶共享。3. 析構(gòu)函數(shù)遞減計(jì)數(shù)器,指出共享狀態(tài)的用戶少了一個(gè)。如果計(jì)數(shù)器變?yōu)?,則析構(gòu)函數(shù)釋放狀態(tài)。4. 拷貝賦值運(yùn)算符遞增右側(cè)運(yùn)算對(duì)象的計(jì)數(shù)器,遞減左側(cè)運(yùn)算對(duì)象的計(jì)數(shù)器。如果左側(cè)運(yùn)算對(duì)象的計(jì)數(shù)器變?yōu)?,意味著它的共享狀態(tài)沒有用戶了,拷貝賦值運(yùn)算符就必須銷毀狀態(tài)。
    • 引用計(jì)數(shù)的存放位置:一種方法只保存在動(dòng)態(tài)內(nèi)存中。當(dāng)創(chuàng)建一個(gè)對(duì)象時(shí),我們也分配一個(gè)計(jì)數(shù)器。當(dāng)拷貝或賦值對(duì)象時(shí),我們拷貝指向計(jì)時(shí)器的指針。使用這種方法,副本和原對(duì)象都會(huì)指向相同的計(jì)數(shù)器。

  • 下面給出一個(gè)基于引用計(jì)數(shù)的共享智能指針的實(shí)現(xiàn)。

    #include<iostream>using namespace std;template<class T>class SmartPtr{public:    //構(gòu)造函數(shù)
        SmartPtr(T *sp = NULL)
            :m_ptr(sp), use_count(new std::size_t(1)){}    //拷貝構(gòu)造函數(shù)
        SmartPtr(const SmartPtr<T> &ref){        if (this != &ref){
                m_ptr = ref.m_ptr;
                use_count = ref.use_count;
                ++*use_count;
            }
        }    //拷貝賦值運(yùn)算符
        SmartPtr& operator=(const SmartPtr<T> &ref){        if (this == &ref)   //處理自賦值情況
                return *this;        //判斷原use_count是否為0
            --*use_count;        if (*use_count == 0){            delete m_ptr;            delete use_count;
                m_ptr = NULL;
                use_count = NULL;            cout << "operator= delete" << endl;
            }
    
            m_ptr = ref.m_ptr;
            use_count = ref.use_count;
            ++*use_count;
        }    //析構(gòu)函數(shù)
        ~SmartPtr(){
            --*use_count; 
            if (*use_count == 0){            delete m_ptr;            delete use_count;
                m_ptr = NULL;
                use_count = NULL;            cout << "~SmartPtr()  and delete" << endl;
            }        else
                cout << "~SmartPtr()  use_count:" << *use_count <<endl;
        }    T * get(){        return m_ptr;
        }    std::size_t getUse_count(){        return *use_count;
        }private:    //基礎(chǔ)對(duì)象指針
        T *m_ptr;    std::size_t *use_count;
    };class Test{public:
        Test(int a, char b) :_a(a), _b(b){}    void print(){        cout << _a << " " << _b << " ";
        }private:    int _a;    char _b;
    };int main(){    //內(nèi)置數(shù)據(jù)類型測(cè)試
        cout << "內(nèi)置數(shù)據(jù)類型測(cè)試" << endl;
        SmartPtr<int> sp1(new int(5));  //默認(rèn)構(gòu)造函數(shù)
        cout << *sp1.get() << "  " << sp1.getUse_count() << endl;
    
        SmartPtr<int> sp2(sp1);  //拷貝構(gòu)造函數(shù)
        cout << *sp2.get() << "  " << sp2.getUse_count() << endl;
    
        SmartPtr<int> sp3;
        sp3 = sp1;          //拷貝賦值運(yùn)算符
        cout << *sp3.get() << "  " << sp3.getUse_count() << endl;
    
        sp3 = sp3;    //自賦值情況
        cout << *sp3.get() << "  " << sp3.getUse_count() << endl;    //自定義數(shù)據(jù)類型測(cè)試
        cout << endl << endl << "自定義數(shù)據(jù)類型測(cè)試" << endl;
        SmartPtr<Test> tp1(new Test(10, 'c'));  //默認(rèn)構(gòu)造函數(shù)
        (tp1.get())->print();    cout << tp1.getUse_count() << endl;
    
        SmartPtr<Test> tp2(tp1);   //拷貝構(gòu)造函數(shù)
        (tp2.get())->print();    cout << tp2.getUse_count() << endl;
    
        SmartPtr<Test> tp3;      
        tp3 = tp1;              //拷貝賦值運(yùn)算符
        (tp3.get())->print();    cout << tp3.getUse_count() << endl;
    
        tp3 = tp3;   //自賦值情況
        (tp3.get())->print();    cout << tp3.getUse_count() << endl;    cout << endl << endl <<  "析構(gòu)函數(shù)" << endl;    return 0; 
    }
  • 程序運(yùn)行結(jié)果如下:
    大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

標(biāo)簽: 拷貝控制智能指針C/C++

http://www.cnblogs.com/lengender-12/p/6658679.html