博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
智能指针的实现
阅读量:6478 次
发布时间:2019-06-23

本文共 4816 字,大约阅读时间需要 16 分钟。

看到了迭代器这里,想到了应该把智能指针的知识总结一下了

我实现了三种智能指针,分别是auto_ptr,scoped_ptr,shared_ptr命名是根据boost库中的智能指针命名的

什么是智能指针?智能指针可以帮助你在忘记释放new出来的内存的时候自动帮助你释放内存
可以有效避免内存泄漏
例如当异常出现,跳转之后。。。内存是应该被释放的呀,一直抓住人家不放会造成内存泄漏哦
智能指针就是RAII(资源分配即初始化)一种典型的应用
 
利用类的构造函数和析构函数来进行内存的开辟和释放,智能指针不能完全说成是指针,它是一种类型用来管理指针的释放,当出了作用域之后,就回去进行内存释放
为了要让智能指针更像一个指针,需要对运算符进行重载:例如*引用
 
 
 
以上就是auto_ptr的部分代码,但是有个很明显的问题,那就是没有拷贝构造函数
当没有书写拷贝构造函数使用默认的拷贝构造函数的时候,这种语句就很危险了,涉及到深浅拷贝的问题,如何解决这种问题呢?
下面就讲!~
auto_ptr ——》自动释放指针(大坑货):拷贝赋值之后,将前一个对象置空,这就完成了只释放一次(当出现拷贝的情况,两个指针分别释放其所指向的同一个空间就会boom!)
scoped_ptr——》守卫——》防拷贝:简单粗暴利用pravate不给你访问权限,不允许拷贝(既然拷贝会出错,那不拷贝不就没事了?)
shared_ptr——》共享——》引用计数:采用指针引用计数的方式进行,不采用普通类型,也不用静态变量,就是要用指针(其实最推荐使用的居然是仿拷贝指针,就是说,没必要拷贝就别拷贝了,必须拷贝再用共享指针)
贴出代码!
1 class AutoPtr 2 { 3 public: 4     explicit AutoPtr(T* ptr=NULL) 5         :_ptr(ptr) 6     { 7     } 8     AutoPtr(AutoPtr& ap) 9         :_ptr(ap._ptr)10     {11         ap._ptr = NULL;12     }13     ~AutoPtr()14     {15         delete _ptr;16     }17     AutoPtr& operator=(AutoPtr& ap)18     {19         if (_ptr != ap._ptr)20         {21             if (NULL == _ptr)22             {23                 _ptr = ap._ptr;24                 ap._ptr = NULL;25             }26             else27             {28                 delete _ptr;29                 _ptr = ap._ptr;30                 ap._ptr = NULL;31             }32         }33         return *this;34     }35     T& operator *()36     {37         return *_ptr;38     }39     T* operator->()40     {41         return _ptr;42     }43     T* GetPtr()44     {45         return _ptr;      46     }47 private:48     T* _ptr;49 };50 51 52 53 void test1()54 {55     AutoPtr
ap1 = new int;//支持强转(这里的意思是,new产生的int *会被强转成auto_ptr指针,就是说会拿int *构造临时的auto_ptr变量然后再赋值)56 AutoPtr
ap2 = new int;57 //AutoPtr
ap3(ap1);//当心,深浅拷贝58 AutoPtr
ap4;59 ap4 = ap1;60 ap2 = ap1;61 /*int *p1 = new int;62 int *p2 = new int;63 delete p1;64 delete p2;*/65 }

PS:最长注释的那句AutoPtr<int > ap1 = new int;如果不希望这种事情发生的话要用到explicit关键字

我把测试用例也贴出来了~auto_ptr的实现还是非常简单的,但是就是太坑了,最好不要使用~

接下来是防拷贝智能指针scoped_ptr

1 #include
2 using namespace std; 3 4 5 6 template
7 class ScopedPtr 8 { 9 public:10 explicit ScopedPtr(T* ptr=NULL)11 :_ptr(ptr)12 {13 }14 ~ScopedPtr()15 {16 if (_ptr)17 {18 delete _ptr;19 }20 }21 T* operator ->()22 {23 return _ptr;24 }25 T& operator *()26 {27 return *_ptr;28 }29 T* GetPtr()30 {31 return _ptr;32 }33 34 private:35 ScopedPtr(ScopedPtr& sp)36 {37 38 }39 ScopedPtr& operator=()40 {41 42 }43 private:44 T* _ptr;45 };46 47 48 49 void test1()50 {51 52 ScopedPtr
sp1 = new int(1);53 ScopedPtr
sp2 = new int(2);54 ScopedPtr
sp3(sp1);55 }

执行这个代码的话就会报编译错误啦,因为拷贝构造放在私有成员里了,是不能使用哒,实现也非常简单,就把关于拷贝的东西全都丢给private就对了

 接下来是共享指针shared_ptr
1 #include
2 using namespace std; 3 template
4 class SharedPtr 5 { 6 public: 7 explicit SharedPtr(T* ptr) 8 :_ptr(ptr) 9 ,_pCount(new int(1))10 {11 12 }13 SharedPtr(SharedPtr& sp)14 :_ptr(sp._ptr)15 ,_pCount(sp._pCount)16 {17 (*_pCount)++;18 }19 ~SharedPtr()20 {21 if (--(*_pCount) == 0)22 {23 delete _ptr;24 delete _pCount;25 }26 }27 SharedPtr& operator=(SharedPtr& sp)28 {29 if (_ptr != sp._ptr)30 {31 if (NULL == _ptr)32 {33 _ptr = sp._ptr;34 _pCount = sp._pCount;35 }36 else37 {38 _Release();39 }40 }41 return *this;42 }43 T& operator*()44 {45 return *_ptr;46 }47 T* operator->()48 {49 return _ptr;50 }51 protected:52 void _AddRef()53 {54 ++(*_pCount);55 }56 void _Release()57 {58 if (--(*_pCount) == 0)59 {60 delete _ptr;61 delete _pCount;62 _ptr = NULL;63 _pCount = NULL;64 }65 }66 private:67 T* _ptr;68 int* _pCount;69 };

引用计数是用指针来实现的,一开始采用的是静态变量,但是有个问题,当声明

1 SharedPtr
s = new int(20);2 SharedPtr
s1=new int (30);

因为存储的数值不同,引用计数应该是不会增长的,但是由于采用了静态变量,该类对象都使用了这个引用计数,就会都往引用计数上加,这就错了

采用指针,开辟出独有的一块空间来管理计数显然才是我们所需要的,析构的时候把delete掉的指针赋空会更好~所以有了Release函数

应该在构造函数之前加上explicit关键字,是为了防止将指针经过转换构造函数变成智能指针,就是防止
int *ptr;
autoptr<int> a;
a=ptr;
这样的转换发生

转载于:https://www.cnblogs.com/lenomirei/p/5363886.html

你可能感兴趣的文章
Spring中jdbcTemplate的用户实例
查看>>
[模板] 快速傅里叶变换/FFT/NTT
查看>>
DecimalFormat 数据格式设置 SimpleDateFormat时间格式的用法介绍 --转载
查看>>
Android 的Margin和Padding属性以及支持的长度单位
查看>>
HDU ACM 1050 Moving Tables
查看>>
Django templates加载css/js/image等静态资源
查看>>
Eclipse C + GTK2.0环境构筑
查看>>
caffe solver
查看>>
Rhel6-heartbeat+lvs配置文档
查看>>
ORACLE分科目统计每科前三名的学生的语句
查看>>
0317复利计算的回顾与总结
查看>>
函数对象
查看>>
最全最新个税计算公式---今天你税了吗?
查看>>
linux shell 正则表达式(BREs,EREs,PREs)差异比较(转,当作资料查)
查看>>
MongoDB--CSharp Driver Quickstart .
查看>>
二分法求平方根(Python实现)
查看>>
使用startActivityForResult方法(转)
查看>>
so在genymotation中错误问题
查看>>
Visual Studio 原生开发的10个调试技巧(二)
查看>>
Windows内核再次出现0Day漏洞 影响win2000到win10所有版本 反病毒软件恐成瞎子
查看>>