中国最好的网站建设有哪些,如何做电商赚钱,wordpress设置静态页面,省建设安全监督站的网站文章目录 智能指针的使用和原理智能指针的使用场景RAII和智能指针C标准库智能指针的使用 智能指针的使用和原理
智能指针的使用场景 1. 下面的程序中#xff0c;new了以后#xff0c;我们也delete了#xff0c;但是因为抛异常导致后面的delete没有得到执行#xff0c;所以… 文章目录 智能指针的使用和原理智能指针的使用场景RAII和智能指针C标准库智能指针的使用 智能指针的使用和原理
智能指针的使用场景 1. 下面的程序中new了以后我们也delete了但是因为抛异常导致后面的delete没有得到执行所以就内存泄漏了所以我们需要new以后捕获异常捕获到异常后delete内存再把异常抛出。 2.但是因为new本身也可能抛异常连续的两个new和下面的Divide都可能会抛异常让我们处理起来很麻烦。智能指针放到这样的场景里面就让问题简单多了。 double Divide(int a, int b)
{// 当b 0时抛出异常if (b 0){throw Divide by zero condition!;}else{return (double)a / (double)b;}
}void Func()
{// 这⾥可以看到如果发⽣除0错误抛出异常另外下⾯的array和array2没有得到释放。// 所以这⾥捕获异常后并不处理异常异常还是交给外⾯处理这⾥捕获了再重新抛出去。// 但是如果array2new的时候抛异常呢就还需要套⼀层捕获释放逻辑这⾥更好解决⽅案// 是智能指针否则代码太戳了int* array1 new int[10];int* array2 new int[10];// 抛异常呢// 连续的两个new// 如果第一个new抛异常可以捕获// 如果第二个new抛异常可以解决delete第二个new// 但是第一个new没有被delete// 这样就需要再第二个new的地方捕获异常,delete第一个new// 如果有很多个new呢,就太麻烦了,这里就需要智能指针了try{int len, time;cin len time;cout Divide(len, time) endl;}catch (...){cout delete [] array1 endl;cout delete [] array2 endl;delete[] array1;delete[] array2;throw; // 异常重新抛出捕获到什么抛出什么}// ...cout delete [] array1 endl;delete[] array1;cout delete [] array2 endl;delete[] array2;
}int main()
{try{Func();}catch (const char* errmsg){cout errmsg endl;}catch (const exception e){cout e.what() endl;}catch (...){cout 未知异常 endl;}return 0;
}RAII和智能指针 1. RAII是获取到资源立即初始化它是一种管理资源的类的设计思想本质是一种利用对象生命周期来管理获取到的动态资源避免资源泄漏这里的资源可以是内存、文件指针、网络连接、互斥锁等等。RAII在获取资源时把资源委托给一个对象接着控制对资源的访问资源在对象的生命周期内始终保持有效最后在对象析构的时候释放资源这样保障了资源的正常释放避免资源泄漏问题。 2. RAII像指针一样 在对象销毁后会正常的释放资源
templateclass T
class SmartPtr
{
public:// RAIISmartPtr(T* ptr):_ptr(ptr){}~SmartPtr(){cout delete[] _ptr endl;delete[] _ptr;}private:T* _ptr;
};double Divide(int a, int b)
{// 当b 0时抛出异常if (b 0){throw Divide by zero condition!;}else{return (double)a / (double)b;}
}void Func()
{// 这⾥可以看到如果发⽣除0错误抛出异常另外下⾯的array和array2没有得到释放。// 所以这⾥捕获异常后并不处理异常异常还是交给外⾯处理这⾥捕获了再重新抛出去。// 但是如果array2new的时候抛异常呢就还需要套⼀层捕获释放逻辑这⾥更好解决⽅案// 是智能指针否则代码太戳了SmartPtrint p1 new int[10];SmartPtrint p2 new int[10];// 抛异常呢SmartPtrint p3 new int[10];int len, time;cin len time;cout Divide(len, time) endl;
}int main()
{try{Func();}catch (const char* errmsg){cout errmsg endl;}catch (const exception e){cout e.what() endl;}catch (...){cout 未知异常 endl;}return 0;
}智能指针类除了满足RAII的设计思路还要方便资源的访问所以智能指针类还像迭代器类一样 重载 operator*/operator-/operator[] 等运算符方便访问资源。 templateclass T
class SmartPtr
{
public:// RAIISmartPtr(T* ptr):_ptr(ptr){}~SmartPtr(){cout delete[] _ptr endl;delete[] _ptr;}// 重载运算符模拟指针的⾏为⽅便访问资源T operator*(){return *_ptr;}T* operator-(){return _ptr;}T operator[](size_t i){return _ptr[i];}private:T* _ptr;
};void Func()
{p1[1] 50;p4-first 1;p4-second 2;cout p1[1] endl;
}C标准库智能指针的使用 浅拷贝的问题共同管理同一块资源而深拷贝是两个指针管理不同的资源了现在要求两个指针管理同一块资源 int main()
{// 需要p1和p2同时管理同一块资源浅拷贝// 析构多次的问题如何解决?SmartPtrint p1 new int[10];SmartPtrint p2(p1);return 0;
}1.C标准库中的智能指针都在 memory 这个头文件下智能指针有好几种除了weak_ptr他们都符合RAII和像指针一样访问的行为原理上而言主要是解决智能指针拷贝时的思路不同。 2. C98的智能指针 1、auto_ptr是C98时设计出来的智能指针它的特点是拷贝时把被拷贝对象的资源的管理权转移给拷贝对象这是⼀个非常糟糕的设计因为他会把被拷贝对象悬空相当于被拷贝对象是空指针了访问报错的问题C11设计出新的智能指针后强烈建议不要使用auto_ptr struct Date
{int _year;int _month;int _day;Date(int year 1, int month 1, int day 1):_year(year), _month(month), _day(day){}// 本身不需要析构,为了验证auto_ptr是否可以解决析构两次的问题~Date(){cout ~Date() endl;}
};int main()
{// 拷⻉时管理权限转移被拷⻉对象ap1悬空auto_ptrDate ap1(new Date);auto_ptrDate ap2(ap1);// 空指针访问ap1对象已经悬空// ap1-_year;return 0;
}C11的智能指针 2、unique_ptr是唯一指针他的特点是不支持拷贝只支持移动。如果不需要拷贝的场景就非常建议使用它。把拷贝构造和拷贝赋值给封delete了 int main()
{unique_ptrDate up1(new Date);不支持拷贝// unique_ptrDate up2(up1);支持移动,移动后up1也悬空了unique_ptrDate up3(move(up1));return 0;
}3、shared_ptr共享指针他的特点是支持拷贝也支持移动。如果需要拷贝的场景就需要使用他了。底层是用引用计数的方式实现的。 int main()
{shared_ptrDate p1(new Date);shared_ptrDate p2(p1);shared_ptrDate p3(p1);cout p1.use_count() endl;// 3p1-_day;cout p1-_day endl; // 2cout p2-_day endl; // 2cout p3-_day endl; // 2return 0;
}4、weak_ptr弱辅助解决shared_ptr的一个问题指针它不同于上面的指针它不支持RAII也就意味着不能用它直接管理资源weak_ptr的产生本质是要解决shared_ptr的一个循环引用导致内存泄漏的问题。