C++ 自己实现智能指针(轻量级)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LHshooter/article/details/83716552

引入

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);。

现在我们来分析下上面的代码

new sp
1p中的p保存
new sp
2p中的p保存
将析构
将析构 delete
将析构
将析构 detele
sp other = new Person
sp 1对象
Person对象
sp tt = temp
sp 2对象
test调用结束
main函数调用结束

改进-增加引用计数

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;  }
};

猜你喜欢

转载自blog.csdn.net/LHshooter/article/details/83716552