#include<iostream>
#include<vector>
using namespace std;
/*
本条款是处理析构函数中抛出异常的情况的
*/
class Widget{
public:
~Widget(){} //假设析构函中可能抛出异常
};
void doSomething()
{
std::vector<Widget> v;
}//在函数结束后v就会被释放掉,并且v中存放的所有类对象也会调用析构函数进行空间释放
//但是如果在调用某个析构函数时遇到错误并抛出了,那整个V的释放过程就中断了,这样就
//产生了一种不确定性。至于为什么析构函数中会出现抛错呢,看看下面的例子
class DBConnection{ //这是一个数据库的连接类
public:
static DBConnection create();//返回一个数据库的连接对象
void close(); //关闭联机,失败则抛出异常
};
class DBConn{ //这是一个数据库的连接管理类
public:
~DBConn()
{
db.close();//将关闭连接的操作放在析构函数中
} //这样析构函数就有了抛错的可能
private:
DBConnection db;
};
//客户就会这样使用,创建一个连接对象给DBConn管理
{//在这个块运行结束后对象就会释放掉
DBConn dbc(DBConnection::create());
}
/*
解决上述问题,我们有三个办法
//方法一:在析构函数中进行捕捉异常,然后进行处理
//方法二:将异常捕获但是不做处理(吞掉)
//方法三:把会产生错误的位置先让客户处理,然后再做“吞掉”处理
*/
//方法一:在析构函数中进行捕捉异常,然后进行处理
DBConn::~DBConn()
{
try{
db.close();
}
catch ("...")
{
std::abort();//直接终止程序,抢先制止“不明确行为”
}
}
//方法二:将异常捕获但是不做处理(吞掉)
DBConn::~DBConn()
{
try{
db.close();
}
catch ("...")
{
//制作运转记录,记下close的调用失败
}
//这种情况析构函数可以正常执行完毕,也就是将错误吞掉了
}
//方法三:把会产生错误的位置先让客户处理,然后再做“吞掉”处理
class DBConn{
private:
bool closed;
DBConnection db;
public:
void close()//让客户先对close进行一次处理,将析构中close的调用当成是双重保险
{ //如果客户关成功了就不在析构函数中调用了
db.close();
closed = true;
}
~DBConn()
{
if (!closed)
{
try{
db.close();
}
catch ("...")
{
//制作运转记录,记下close的调用失败
}
//这种情况析构函数可以正常执行完毕,也就是将错误吞掉了
}
}
};
//析构函数中注定是无法妥善处理异常的,所以我们会尽量让客户去处理异常,如果客户都没有处理
//那也不会埋怨析构函数的操作了