C++ 自己實現智慧指標(輕量級)
阿新 • • 發佈:2018-11-06
文章目錄
引入
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; }
};