目录
引入
回顾上一篇章,学习了异常机制,但面临了一种情况还没有解决,就是异常带来的内存泄漏,如下:
#include <iostream>
using namespace std;
double Division(int a, int b)
{
// 当b == 0时抛出异常
if (b == 0)
throw "Division by zero condition!";//抛出的异常是字符串
else
return ((double)a / (double)b);
}
void Func()
{
int* p = new int[1];
int len, time;
cin >> len >> time;
cout << Division(len, time) << endl;
delete[] p;
}
int main() {
try
{
Func();
}
catch (const char* errmsg)
{
cout << "Caught in main: " << errmsg << endl;
}
return 0;
}
调用Division函数时,若抛出异常,最终是被main函数中的catch所捕获,直接进入到main函数中的catch中了,但是,delete[] p不会被执行了 ,导致的问题就是内存泄漏。那么可以通过智能指针来解决这个问题
一、智能指针的使用及原理
1.1RAII
RAII是一种利用对象生命周期来控制程序资源的简单技术。在对象构造时获取对象资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候由编译器顺带释放资源。实际上把控资源就是管理对象。
这种做法体现的优势是:
- 不需要显示地释放资源
- 采用这种方式,对象所需的资源在其生命期内始终保持有效
RAII是一种设计思想,而智能指针正是采用了这种思想。
RAII思想设计:
#include <iostream>
using namespace std;
// 使用RAII思想设计的SmartPtr类
template<class T>
class SmartPtr {
public:
SmartPtr(T* ptr = nullptr)
:_ptr(ptr)
{}
~SmartPtr()
{
if (_ptr)
delete _ptr;
}
private:
T* _ptr;
};
double Division(int a, int b)
{
// 当b == 0时抛出异常
if (b == 0)
throw "Division by zero condition!";//抛出的异常是字符串
else
return ((double)a / (double)b);
}
void Func()
{
int* p = new int[1];
int len, time;
cin >> len >> time;
cout << Division(len, time) << endl;
SmartPtr<int> sp(p);//当Division抛异常时,会被main函数中的catch捕获,那么程序会直接跳到main函数所在的catch
//对此了,Func函数的栈帧会自动销毁,对于内置类型会自动释放,对于自定义类型而言会去调用它的析构函数
//所以sp会去调用析构函数,同时释放了p的资源
}
int main() {
try
{
Func();
}
catch (const char* errmsg)
{
cout << "Caught in main: " << errmsg << endl;
}
return 0;
}
输出结果:
1.2智能指针原理
上述的SmartPtr虽然是通过RAII思想设计的类,但还不能真正称作为智能指针,因为它还不有指针的行为。指针可以解引用,也可以通过->去访问所指空间的内容,因此还需要重载*和->。
#include <iostream>
using namespace std;
template<class T>
class SmartPtr {
public:
SmartPtr(T* ptr = nullptr)
: _ptr(ptr)
{}
~SmartPtr()
{
if (_ptr)
delete _ptr;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
struct Date
{
int _year;
int _month;
int _day;
};
int main()
{
SmartPtr<int> sp1(new int);
*sp1 = 10;
cout << *sp1 << endl;
SmartPtr<Date> sparray(new Date);
sparray->_year = 2024;
sparray->_month = 7;
sparray->_day = 7;
cout << (*sparray)._year << ":" << (*sparray)._month << ":" << (*sparray)._day << endl;
return 0;
}
输出结果: