1. 程式人生 > >C++ 自己實現智慧指標(輕量級)

C++ 自己實現智慧指標(輕量級)

文章目錄

引入

c++的堆和棧

class Person{
		public:
				Person(){ cout<<"new Person"<<endl; }
				~Person(){  cout<<"~ Person"<<endl;  }
};
int main(){
	Person m;
	Person* tt = new Person();
	return 0;
}

程式執行結果:
 	new person
	new person
	~Person

注意到,解構函式只調用了一次,即m在main函式執行完作為棧變數被釋放
Person m; 會存放在棧裡面,
而Person* tt = new Person();存放在堆裡面(需要自己delete釋放堆空間)

那麼如果都是存放在棧裡面是不是就可以自己析構,就可以自回收
因此我們可以引入一個類作為中間類

c++中間類

class Person{
		public:
				Person(){ cout<<"new Person"<<endl; }
				~Person(){  cout<<"~ Person"<<endl;  }
				void print(){  cout<<"...out Person..."<<endl;  }
};
class sp{
	private:
				Person *p;
	public:
				sp(){  cout<<"new sp"<<endl;  }
				~sp(){  cout<<"~ sp"<<endl;  if(p) {cout<<p<<endl; delete(p);} }
				sp(Person *per){   p=per;    cout<<"new sp Person*per"<<endl;  }
				sp(const sp &pers){   p=pers.p;  cout<<"new sp"<<endl;  }
				Person* operator->(){  return p;  } //定義->的操作功能
				Person& operator*(){	return *p;	}
};
void test(){	sp other = new Person();	}
int main(){
	test();
	return 0;
}

程式執行結果:
		new Person
		new sp
		~sp
		~ Person

注意到~sp(){ if(p) delete(p); } 如果會delete,但是第二次if(p),new Person 仍然不會析構
sp other = new Person(); 實際相當於兩步 Person *tmp = new Person(); sp other = *tmp–>即呼叫 sp()的建構函式

如果程式碼稍微修改下

void test(sp &temp){	sp tt = temp;  tt->print()	}
int main(){
	sp other = new Person();
	test(other);
	return 0;
}
執行會奔潰:
new Person
new sp Person *per
new sp sp &pers
~sp
0x1d9a010
~ Person
0
~sp
0x1d9a010
~ Person
*** glibc detected *** ./pointer: double free or corruption (fasttop): 0x0000000001d9a010 ***

 錯誤1: 建立了兩個sp ,會執行兩次析構 ~sp  而 if(p) delete(p); 這裡判斷會呼叫兩次。sp other = new Person(); test(other);。

現在我們來分析下上面的程式碼

改進-增加引用計數

sp other = new Person();
test(other);
上面兩行程式碼的問題在於,sp有一個引用sp tt,呼叫結束,tt是儲存在棧中,呼叫結束tt將呼叫sp的解構函式。當回撥主函式other又是一個棧中的物件,則又會呼叫一次解構函式,而if(p)的判斷這裡似乎無效。
在sp中,Person 是通過sp來呼叫,Person的析構也由sp掌握,因此只有當確認Person不再被任何sp物件(引用)呼叫時,才delete Person。
每new sp 且給 Person *p賦值處增加引用計數,在析構中引用遞減

class Refbase{
private:
        int count;
public:
        Refbase():count(0){}
        void incStrong(){ count++; }
        void decStrong(){ count--; }
        int getStrongCount(){ return count;  }
};

class Person:public Refbase{
public:
        Person(){
                cout<<"new Person"<<endl;
        }
        Person(const Person &t){
                cout<<"new Person t"<<endl;
        }
        Person(Person *tt){
                cout<<"new Person *tt"<<endl;
        }
        ~Person(){
                cout<<"~ Person"<<endl;
        }
        void print(){  cout<<"cout person"<<endl;  }
};
class sp{
private:
        Person *p;
public:
        sp():p(0){  cout<<"new sp"<<endl;  }
        ~sp(){
                cout<<"~sp"<<endl;
                if(p){
                        p->decStrong();
                        if(p->getStrongCount() == 0){
                                delete(p);
                                p = NULL;
                                cout<<p<<endl;
                        }
                }
        }
        sp(Person *per){
                p=per;
                p->incStrong();
                cout<<"new sp Person *per"<<endl;  }
        sp(const sp &pers){
                p=pers.p;
                p->incStrong();
                cout<<"new sp sp &pers"<<endl;  }
        Person* operator->(){  return p;  } //定義->的操作功能
        Person& operator*(){    return *p;      }
};
void test(sp &tmp){
        sp other = tmp;
        other->print();
}
int main(){
        sp oth = new Person();
        test(oth);
        cout<<"this is test"<<endl;
        return 0;
}

再次改進–使用模板template

使用template<typename T>類模板來操作,但是要注意,必須要每個使用的函式錢新增類模板定義

using namespace std;
class Refbase{
private:
        int count;
public:
        Refbase():count(0){}
        void incStrong(){ count++; }
        void decStrong(){ count--; }
        int getStrongCount(){ return count;  }
};

class Person:public Refbase{
public:
        Person(){
                cout<<"new Person"<<endl;
        }
        Person(const Person &t){
                cout<<"new Person t"<<endl;
        }
        Person(Person *tt){
                cout<<"new Person *tt"<<endl;
        }
        ~Person(){
                cout<<"~ Person"<<endl;
        }
        void print(){  cout<<"cout person"<<endl;  }
};
template<typename T>
class sp{
private:
        T *p;
        int vale;
public:
        sp():p(0),vale(0){  cout<<"new sp"<<endl;  }
        ~sp(){
                cout<<"~sp"<<endl;
                if(p){
                        p->decStrong();
                        if(p->getStrongCount() == 0){
                                delete(p);
                                p = NULL;
                        }
                }
        }
        sp(T *per){
                vale = 1;
                p=per;
                p->incStrong();
                cout<<"new sp T *per"<<endl;  }
        sp(const sp &pers){
                p=pers.p;
                vale = 2;
                p->incStrong();
                cout<<"new sp sp &pers"<<endl;  }
        T* operator->(){  return p;  } //定義->的操作功能
        T& operator*(){ return *p;      }
};
template<typename T>
void test(sp<T> &tmp){
        sp<T> other = tmp;
}
int main(){
         sp<Person> oth = new Person();
        test(oth);
        return 0;
}

再次改進–引用計數增加原子操作

ctemplate<typename T>
class Refbase{
private:
        mutable volatile int32_t count;
public:
        Refbase():count(0){}
        void incStrong(){
                 __sync_fetch_and_add(&count, 1);
                //count++;
        }
        void decStrong(){ 
                //count--;
                if (__sync_fetch_and_sub(&count, 1) == 1) {
                        delete static_cast<const T*>(this); //注意這裡實現了delete操作
                }
        }
        int getStrongCount(){ return count;  }
};