RAII
资源获得及初始化,获得资源马上进行初始化
是一种利用对象生命周期来控制程序资源(如内存、文件句 柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。
//智能指针专门用来管理动态开辟的空间
//RAII不等价于只能指针
//RAII是解决问题的思想
//智能指针是RAII思想的一种实现
template<class T>
class SmartPtr
{
public:
SmartPtr(T* ptr) //在构造函数时保存动态开辟空间的指针
:_ptr(ptr)
{
}
~SmartPtr() //在析构函数中释放
{
delete _ptr;
}
T* get()
{
return _ptr;
}
T* operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
//托管
SmartPtr<int*> sp(new int); //这样在外界无法访问,需要重载 operator*() operator->()
//这样,就算抛异常导致结束时未释放资源,函数结束销毁对象时会自动调用析构函数
auto_ptr
//模仿实现
template<class T>
class auto_ptr //C++98
{
public:
auto_ptr(T* ptr) //在构造函数时保存动态开辟空间的指针
:_ptr(ptr)
{
}
~auto_ptr() //在析构函数中释放
{
delete _ptr;
}
T* operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
//管理权转移
auto_ptr(const auto_ptr<T>& ap)
:_ptr(ap._ptr) // 这样就解决了一块空间被多个对象使用而造成程序奔溃问题
{
ap._ptr = nullptr; //把两个对象中的指针变为一个
}
auto_ptr<T>& operator=(const auto_ptr<T>& ap)
{
if(this != &ap) // 检测是否为自己给自己赋值
{
if(_ptr) // 释放当前对象中资源
{
delete _ptr; //放置在赋值时这个对象本身就指向空间,赋值时而忘记释放
}
_ptr = ap._ptr; // 转移资源到当前对象中
ap._ptr = nullptr;
}
return *this;
}
//测试函数
void test_auto_ptr()
{
auto_ptr<int> ap1(new int);
auto_ptr<int> ap2(ap1); //不定义拷贝构造则浅拷贝,释放两次
*ap1 = 10; //报错 访问空指针
ap1 = ap3;
}
private:
T* _ptr;
};
void test_auto_ptr()
{
//库中的auto_pr
std::auto_ptr<int> ap1(new int);
std::auto_ptr<int> ap2(ap1);,//多次释放
*ap1 = 10; //崩溃, ap1已经成为nullptr
}
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;
}
//不允许拷贝和赋值
C++98防拷贝的方式:只声明不实现+声明成私有
// C++11防拷贝的方式:delete
unique_ptr(const unique_ptr<T>& up) = delete;
unique_ptr<T>& operator=(const unique_ptr<T>& up) = delete;
//测试函数
void test_unique_ptr() //自己实现
{
std::unique_ptr<int> ap1(new int);
std::unique_ptr<int> ap2(ap1); //报错,不能实现
}
private:
T* _ptr;
};