智能指针的实现


看到了迭代器这里,想到了应该把智能指针的知识总结一下了,我实现了三种智能指针,分别是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             else
27             {
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<int > ap1 = new int;//支持强转(这里的意思是,new产生的int *会被强转成auto_ptr指针,就是说会拿int *构造临时的auto_ptr变量然后再赋值)
56     AutoPtr<int > ap2 = new int;
57     //AutoPtr<int >ap3(ap1);//当心,深浅拷贝
58     AutoPtr<int > 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<iostream>
 2 using namespace std;
 3 
 4 
 5 
 6 template<class T>
 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<int> sp1 = new int(1);
53     ScopedPtr<int> sp2 = new int(2);
54     ScopedPtr<int> sp3(sp1);
55 }

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

 接下来是共享指针shared_ptr
 1 #include<iostream>
 2 using namespace std;
 3 template<class T>
 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             else
37             {
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<int> s = new int(20);
2 SharedPtr<int> s1=new int (30);

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

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

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

本文永久更新链接地址

相关内容