zoukankan      html  css  js  c++  java
  • 智能指针的实现

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

    我实现了三种智能指针,分别是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;
    这样的转换发生
  • 相关阅读:
    Linuxboot:linux as UEFI,linux over UEFI
    在阿里云上安装黑苹果的一种设想
    Dsm as deepin mate(3):离线编辑初始镜像,让skynas本地验证启动安装/升级
    硬件融合的新起点:虚拟firmware,avatt的编译(2)
    将虚拟机集成在BIOS和EFI层,vavvt的编译(1)
    2013.08.19—2013.08.23周总结
    关于自我介绍
    Java入门系列:实例讲解ArrayList用法
    Hadoop文件的基本操作
    继承关系的理解
  • 原文地址:https://www.cnblogs.com/lenomirei/p/5363886.html
Copyright © 2011-2022 走看看