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é)果如下:
http://www.cnblogs.com/lengender-12/p/6658679.html