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