RAII智能指针

2023-12-20 21:32:19

RAII
resource acquisition is initialization RAII是利用对象声明周期来控制程序资源的简单技术
在对象构造时获取资源,控制着对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给一个对象
好处:
①.不需要显式地释放资源
②.采用这种方式,对象所需的资源在其生命周期内始终有效
智能指针
auto_ptr
智能指针本质就是一个类模板,可以创建任意类型的指针对象,当智能指针对象使用完后,对象就会自动调用析构函数去释放指针所指向的空间

template<class T>
class auto_ptr{
   auto_ptr(T*ptr)
  _ptr(ptr)
  {}   
  auto_ptr(auto_ptr<T>&ap)
  :_ptr(ap._ptr)
 {
   ap._ptr=nullptr;
 }
  auto_ptr<T>&operartor=(auto_ptr<T>&ap){
     if(_ptr!=ap._ptr_)
     { 
       _ptr=ap._ptr;
        _ap._ptr=nullptr;
     }
     return *this;
     }
  }
 ~auto_ptr(){
 if(_ptr){
 delete _ptr;
 _ptr=nullptr;
 }
 }
   T&operator(){
   return *_ptr;
   }
   T*operator->(){
   return _ptr;
   }
  private:
  T*_ptr;
}

auto_ptr管理权转移,最后一个拷贝对象管理资源,被拷贝对象都置空
原对象拷贝给新对象时,原对象就会被设置为nullptr,此时只有新对象指向一块资源空间
如果auto_ptr调用拷贝构造函数或者赋值重载函数后再去使用原来的对象,由于原对象已被设置成nullptr,程序可能崩溃
关于库auto_ptr的其它函数
release,reset
在这里插入图片描述在这里插入图片描述

auto_ptr myAutoPtr(new int(42));
// 释放内存并设置新值
myAutoPtr.reset(new int(99));
// 释放所有权而不析构对象
int* releasedPtr = myAutoPtr.release();
// 此时,myAutoPtr 不再拥有内存的所有权
// 不要忘记手动删除内存,因为所有权已被释放
delete releasedPtr;

unique_ptr

template<class T>
class  unique_ptr{
  public:
    unique_ptr(T*ptr)
    :_ptr(ptr)
    {}
    ~unique_ptr(){
      delete _ptr;
    }
    T&operator*(){
    return  *_ptr;
    }
    T*operator->(){
    return _ptr;
    }
    unique_ptr<T>operartor=(const unique_ptr<T>&up)=delete;
    unique_ptr(const unique_ptr<T>&up)=delete;
   private:
   T*_ptr;
}

shared_ptr
shared_ptr采用的是引用计数原理来实现多个shared_ptr之间共享资源
shared_ptr在内部维护着一份引用计数,用来记录该资源被几个对象共享
当一个shared_ptr对象被销毁时(调用析构函数),析构函数内就会将该计数减1
如果引用计数减为0,则表示自己是最后一个使用该资源的shared_ptr对象,必须释放
如果引用计数不是0,就说明自己还有其他对象在使用,则不能释放资源,否则其他对象就成为野指针

template<class T>
class shared_ptr{
     shared_ptr(T*ptr=nullptr)
     :_ptr(ptr)
     ,_pcount(new int(1))
     {}
     template<class D>
     shared_ptr(T*ptr,D del)
     :_ptr(ptr)
     ,_pcount(new int(1))
     ,_del(del)
     {}
     void release(){
         if(--*(_pcount)==0){
             _del(_ptr);
             delete _pcount;
         }
     }
     shared_ptr(const shared_ptr<T>&sp)
     :_ptr(sp._ptr)
     :_pcount(sp._pcount)
     {*(_pcount)++;}
     shared_ptr<T>operator=(const shared_ptr<T>&sp)
     {
           if(_ptr!=sp._ptr){
                release();
                _ptr=sp._ptr;
                _pcount=sp._pcount;
                ++(*_pcount);
           }
           return *this;
     }
     ~shared_ptr(){
       release();
     }
     T&operator*(){
     return *_ptr;
     }
     T*operator->(){
     return  _ptr; 
     }
     int use_count()const
     {
     return *_pcount;
     }
     T*get()const{
     return _ptr;
     }
     private:
     T*_ptr;
     int*_pcount;
     //定制删除器
     function<void(T*)>del=[](T*ptr){delete ptr;};
}

shared_ptr的循环引用
shared_ptr固然好用,但是它也会有问题存在。假设我们要使用定义一个双向链表,如果我们想要让创建出来的链表的节点都定义成shared_ptr智能指针,那么也需要将节点内的_pre和_next都定义成shared_ptr的智能指针。如果定义成普通指针,那么就不能赋值给shared_ptr的智能指针。
weak_ptr类的对象它可以指向shared_ptr,并且不会改变shared_ptr的引用计数。一旦最后一个shared_ptr被销毁时,对象就会被释放

template<class T>
class weak_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;
}
T*operator->(){
	return _ptr;
}
T&operator*(){
	return *_ptr;
}
private:
	T*_ptr;

};

文章来源:https://blog.csdn.net/C1238888/article/details/135116193
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。