文章目录 
为了解决指针资源忘记或没有删除导致的内存泄露问题,C++就出现了智能指针的机制,可以在使用的时候初始化,在离开作用域之后就自动析构,删除资源
C++98的智能指针 auto_ptr的模拟实现 auto_ptr是最早期的智能指针形态, 它可以实现在
构造函数里面初始化 
在析构函数里面将资源销毁,不用我们去显示调用,避免内存泄露 
但是它无法解决拷贝构造的问题,它是浅拷贝(会造成资源被多次析构)(使用管理权转移的方式来进行拷贝构造即构造之后,自己的资源就没了) 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 namespace  xzw {     template  <class  T >     class  auto_ptr      {     private :         T *_ptr;     public :                  auto_ptr (T *ptr)             : _ptr(ptr)          {         }         ~auto_ptr ()         {             if  (_ptr)             {                 cout << "delete"  << endl;                 delete  _ptr;              }         }                  auto_ptr (auto_ptr<T> &sp)             : _ptr(sp._ptr)         {                                       sp._ptr = nullptr ;          }         T &operator *()         {             return  *_ptr;         }         T *operator ->()          {             return  _ptr;         }     }; };void  demo1 ()  {     int  *p1 = new  int ;     xzw::auto_ptr<int > sp1 (p1)  ;      int  *p2 = new  int ;     xzw::auto_ptr<int > sp2 (sp1)  ;          xzw::auto_ptr<int > sp3 (new  int )  ;      *sp3 = 10 ;     cout << __LINE__ << *sp3 << endl;     cout << *sp1 << endl;            }
 
实际工作中绝对不能使用auto_ptr 
C++11的智能指针 定制删除器 默认情况下,智能指针底层的删除器都是用delete 但是不同的资源销毁的方式不同,直接用delete十分暴力,不合理,所以就有了定制删除器
比如:
malloc -> free 
open -> close 
fopen -> fclose 
new[] -> delete[] … 
 
我们在下文会详细解释
unique_ptr的模拟实现 unique_ptr对于拷贝构造的解决方式即直接把拷贝构造给禁止了 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 namespace  Uni_Ptr {         template  <class  T >     class  defult_delete      {     public :         void  operator () (const  T* ptr)          {             cout<<__LINE__<<endl;             cout<<"delete" <<endl;             delete  ptr;         }     };     template  <class  T , class  D =default_delete<T>>          class  unique_ptr     {     private :         T *_ptr;         unique_ptr (const  unique_ptr<T> &sp) = delete ;      public :                  unique_ptr (T *ptr)             : _ptr(ptr)          {         }         ~unique_ptr ()         {             if  (_ptr)             {                                                   D del;                 del (_ptr);             }         }         T &operator *()         {             return  *_ptr;         }         T *operator ->()          {             return  _ptr;         }     }; };
 
1 2 3 4 5 6 void  demo2 ()  {     Uni_Ptr::unique_ptr<int > sp1 (new  int )  ;           }
 
unique_ptr对于定制删除器的使用,就是我们在外面写一个类的仿函数,在模板里面进行传参即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 template  <class  T >struct  DeleteArray  {     void  operator () (const  T *ptr)      {         cout << "delete[]"  << endl;         delete [] ptr;     } };#include <cstdio>  #include <stdio.h>  struct  DeleteFile  {     void  operator () (FILE *ptr)      {         cout << "fclose:"  << endl;         fclose (ptr);     } };void  demo6 ()  {                         Uni_Ptr::unique_ptr<Date> s (new  Date)  ;     Uni_Ptr::unique_ptr<Date, DeleteArray<Date>> s1 (new  Date[10 ]);      Uni_Ptr::unique_ptr<FILE,DeleteFile> s2 (fopen("1.txt" ,"w" ))  ; }
 
shared_ptr的模拟实现 shared_ptr是为了解决unique_ptr无法实现拷贝构造 新增加了一个引用计数的机制:
同一个对象只能有一个引用计数,当调用构造函数的时候,第一个引用计数出现为1,后续如果有发生拷贝构造,引用计数就+1,当析构的时候,引用计数就-1,直到引用计数为0的时候,这个资源就销毁
 
即由最后一个管理的对象来进行对资源的释放
 
智能指针是线程安全的,因为对里面的引用计数进行了加锁处理,但是指向的资源不是线程安全的,这个需要使用者手动处理 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 namespace  Shared_Ptr {          template  <class  T >     class  defult_delete      {     public :         void  operator () (const  T* ptr)          {             cout<<__LINE__<<endl;             delete  ptr;         }     };     template  <class  T , class  D =default_delete<T>>     class  shared_ptr     {     private :         T *_ptr;                  int  *_pRefCount;                   mutex *_mtx;      public :                  shared_ptr (T *ptr)             : _ptr(ptr), _pRefCount(new  int (1 )), _mtx(new  mutex)          {                                   }         shared_ptr (const  shared_ptr<T> &sp)                                        : _ptr(sp._ptr), _pRefCount(sp._pRefCount), _mtx(sp._mtx)          {                                       AddRef ();         }         ~shared_ptr ()         {             Release ();         }         T *get ()  const           {             return  _ptr;         }                  T &operator *()         {             return  *_ptr;         }         T *operator ->()          {             return  _ptr;         }         void  Release ()          {             _mtx->lock ();                          (*_pRefCount)--;              bool  flag = false ;             if  (!(*_pRefCount) && _ptr)             {                 cout << "delete"  << endl;                 delete  _ptr;                  delete  _pRefCount;                 _ptr = nullptr ;                 _pRefCount = nullptr ;                 flag = true ;                              }             _mtx->unlock ();             if  (flag)             {                 delete  _mtx;                 _mtx = nullptr ;             }         }         void  AddRef ()          {             _mtx->lock ();             (*_pRefCount)++;             _mtx->unlock ();         }         shared_ptr<T> &operator =(const  shared_ptr<T> &sp)          {             if  (_ptr != sp._ptr)              {                                  Release ();                 _ptr = sp._ptr;                              _pRefCount = sp._pRefCount;                  _mtx = sp._mtx;                 AddRef ();             }             return  *this ;         }     };     };
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 void  demo3 ()  {     Shared_Ptr::shared_ptr<int > sp (new  int )  ;     Shared_Ptr::shared_ptr<int > sp1 (sp)  ;     Shared_Ptr::shared_ptr<int > sp2 (sp)  ;     Shared_Ptr::shared_ptr<int > sp3 (sp)  ;     Shared_Ptr::shared_ptr<int > sp4 (new  int (3 ))  ;      sp1 = sp4;     sp2 = sp4;     sp = sp4;                    *sp4 = 3 ;     *sp = 4 ;     cout << (*sp3) << endl;     cout << __LINE__ << endl; }
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 struct  Date  {     int  _year = 1 ;     int  _month = 1 ;     int  _day = 1 ; };void  SharePtreFunc (Shared_Ptr::shared_ptr<Date> &sp, size_t  n, mutex &mtx)  {     for  (int  i = 0 ; i < n; i++)     {         Shared_Ptr::shared_ptr<Date> copy (sp)  ;                  {                          unique_lock<mutex> lock (mtx)  ;              copy->_day++;             copy->_month++;             copy->_year++;                          lock.unlock ();         }         cout << "hello"  << endl;      } }void  demo4 ()  {     Shared_Ptr::shared_ptr<Date> p (new  Date)  ;     const  size_t  n = 10000000 ;     mutex mtx;     thread t1 (SharePtreFunc, std::ref(p), n, std::ref(mtx))  ;      thread t2 (SharePtreFunc, std::ref(p), n, std::ref(mtx))  ;     t1.join ();     t2.join ();     cout << p->_day << endl;     cout << p->_month << endl;     cout << p->_year << endl; }
 
shared_ptr对于定制删除器的使用:就是在构造函数的时候加上,该可调用对象(函数指针,仿函数,lambda表达式) 使用lambda表达式最方便
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 template  <class  T >struct  DeleteArray  {     void  operator () (const  T *ptr)      {         cout << "delete[]"  << endl;         delete [] ptr;     } };#include <cstdio>  #include <stdio.h>  struct  DeleteFile  {     void  operator () (FILE *ptr)      {         cout << "fclose:"  << endl;         fclose (ptr);     } };void  demo6 ()  {          std::shared_ptr<Date> srp (new  Date)  ;     std::shared_ptr<Date> srp4 (new  Date[10 ],DeleteArray<Date>())  ;               std::shared_ptr<Date> srp3 (new  Date[10 ],[](Date* ptr){cout<<"delete []" <<endl;      delete [] ptr;})  ;          std::shared_ptr<FILE> srp1 (fopen("1.txt" ,"w" ),DeleteFile())  ;     std::shared_ptr<FILE> srp2 (fopen("1.txt" ,"w" ),[](FILE* ptr){fclose(ptr);})  ; }
 
weak_ptr shared_ptr会出现循环引用的问题 一个指针,你里面有一个智能指针,指向我,我里面有一个智能指针指向你,这就是循环引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 struct  ListNode  {     int  _val;      shared_ptr<ListNode> _prev;      shared_ptr<ListNode> _next; };void  demo5 ()  {     shared_ptr<ListNode> n1 (new  ListNode)  ;     shared_ptr<ListNode> n2 (new  ListNode)  ;     cout << n1.use_count () << endl;     cout << n2.use_count () << endl;           n1->_prev=n2;      n2->_next=n1;     cout << n1.use_count () << endl;     cout << n2.use_count () << endl; }
 
这样子会出现问题
weak_ptr是一个弱指针,没有引用计数的机制,可以支持shared_ptr对它进行拷贝构造和赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44   template  <class  T >     class  weak_ptr      {     private :         T *_ptr;     public :         weak_ptr ()             : _ptr(nullptr )         {         }         weak_ptr (const  shared_ptr<T> &sp)             : _ptr(sp.get ())         {         }         weak_ptr<T> &operator =(const  shared_ptr<T> &sp)         {             _ptr = sp.get ();             return  *this ;         }     }; 	struct  ListNode  {     int  _val;     Shared_Ptr::weak_ptr<ListNode> _prev;      Shared_Ptr::weak_ptr<ListNode> _next;      };void  demo5 ()  {     shared_ptr<ListNode> n1 (new  ListNode)  ;     shared_ptr<ListNode> n2 (new  ListNode)  ;     cout << n1.use_count () << endl;     cout << n2.use_count () << endl;           n1->_prev=n2;      n2->_next=n1;     cout << n1.use_count () << endl;     cout << n2.use_count () << endl; }
 
总结一点:如果使用对象的话,就要用强指针,如果要引用一个对象的话,就要用弱指针 即weak_ptr不会参与空间资源的管理,只是作为一个解决循环引用的工具