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;};