EC读书笔记系列之4:条款8 别让异常逃离析构函数
条款8 别让异常逃离析构函数
记住:
★析构函数绝对不要吐出异常。若一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序。
★若客户需对某个操作函数运行期间抛出的异常做出反应,那么class应提供一个普通函数(而非在析构函数)执行该操作。
-----------------------------------------------------------------------------------------------------------------------------------------
问题背景:
class Widget {
public:
...
~Widget() {...} //假设这个可能吐出一个异常
};
void doSomething() {
std::vector<Widget> v;
...
}
当容器v被销毁时,其有责任销毁其内含的所有Widgets。假设v内含十个Widgets,而在析构第一个元素期间,有个异常被抛出,此时其他九个Widgets还是应该被销毁,因此v应该调用它们各个析构函数。但假设在那些调用期间,第二个Widget析构函数又抛出异常。现在有两个同时作用的异常,在此情况下,程序若不是结束执行就是导致不明确行为!!!
若你的析构函数必须执行一个动作,而该动作可能会抛出异常,该怎么办?举例如下:
class DBConnection { //此类负责数据库连接
public:
...
static DBConnection create();
void close(); //关闭数据库连接,失败时会抛出异常
};
class DBConn { //此class用来管理DBConnection对象
public:
...
~DBConn() {
db.close(); //确保数据库连接总会被关闭
}
private:
DBConnection db;
}
客户很可能会写出如下代码:
{
DBConn dbc( DBConnection::create() )
...
//在区块结束点,DBConn对象被销毁,∴自动为DBConnection对象调用close
}
若调用close()成功一切好说;若该调用导致异常,DBConn析构函数会传播该异常,也即允许它离开这个析构函数,这就会造成问题!!!
三个办法可以解决:(前两个方法无吸引力,第三个是较佳策略)
方法一:若close抛出异常就结束程序:
DBConn::~DBConn() {
try {
db.close();
}
catch(...) { //...表示捕获所有的异常
只做运转记录,记下对close的调用失败
std::abort();
}
}
方法二:吞下因调用close而发生的异常
DBConn::~DBConn() {
try {
db.close();
}
catch(...) {
制作运转记录,记下对close的调用失败
}
}
方法三:较佳策略
重新设计DBConn接口,使其客户有机会对可能出现的问题作出反应(即让客户自己参与!):
class DBConn {
public:
...
void close() { //供客户使用的新函数
db.close();
closed = true;
}
~DBConn() {
if( !closed ) {//若客户忘了调用close函数,则由destructor来关闭,这是双保险
try {
db.close();
}
catch(...) { //吞下所有异常
制作运转记录,记下对close的调用失败
}
}
}
private:
DBConnection db;
bool closed;
};
EC读书笔记系列之4:条款8 别让异常逃离析构函数的更多相关文章
- EC读书笔记系列之16:条款35、36、37、38、39、40
条款35 考虑virtual函数以外的其他选择 记住: ★virtual函数的替代方案包括NVI手法及Strategy模式的多种形式.NVI手法自身是一个特殊形式的Template Method模式 ...
- EC读书笔记系列之1:条款1、条款2、条款3
条款1:视C++为一个语言联邦 记住: ★C++高效编程守则视状况而变化,这取决于你使用C++的哪一部分 C: Object-oriented c++: Template c++: STL 条款2:尽 ...
- EC读书笔记系列之20:条款53、54、55
条款53 不要轻忽编译器的警告 记住: ★严肃对待编译器发出的警告信息.努力在你的编译器的最高(最严苛)警告级别下争取“无任何警告”的荣誉 ★不要过度依赖编译器的报警能力,∵不同的编译器对待事情的态度 ...
- EC读书笔记系列之19:条款49、50、51、52
条款49 了解new-handler的行为 记住: ★set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用 ★Nothrow new是一个颇为局限的工具,∵其只适用于内存 ...
- EC读书笔记系列之18:条款47、48
条款47 请使用traits classes表现类型信息 记住: ★Traits classes使得“类型相关信息”在编译期可用.它们以templates和“templates特化”完成实现 ★整合重 ...
- EC读书笔记系列之17:条款41、42、43、44、45、46
条款41 了解隐式接口与编译器多态 记住: ★classes和templates都支持接口和多态 ★对classes而言接口是显式的(explicit),以函数签名为中心.多态则是通过virtual函 ...
- EC读书笔记系列之15:条款32、33、34
条款32 确保你的public继承塑模出is-a关系 记住: ★public继承意味着is-a.适用于base class身上的每一件事情一定也适用于derived class身上,∵每一个deriv ...
- EC读书笔记系列之14:条款26、27、28、29、30、31
条款26 尽可能延后变量定义式的出现时间(Lazy evaluation) 记住: ★尽可能延后变量定义式的出现.这样做可增加程序的清晰度并改善程序效率 ----------------------- ...
- EC读书笔记系列之12:条款22、23、24
条款22 将成员变量声明为private 记住: ★切记将成员变量声明为private.这可赋予客户访问数据的一致性.可细微划分访问控制.允诺约束条件获得保证,并提供class作者以充分的实现弹性. ...
随机推荐
- paip.vs2010 或.net 4.0安装出错解决大法.
paip.vs2010 或.net 4.0安装出错解决大法. 作者Attilax , EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.cs ...
- golang之interface
一.概述 接口类型是对 "其他类型行为" 的抽象和概况:因为接口类型不会和特定的实现细节绑定在一起:很多面向对象都有类似接口概念,但Golang语言中interface的独特之处在 ...
- linq to sql简单使用
1.新建一个winform项目. 2.添加一个Linq to Sql 类,命名为Northwind 3.打开服务器资源管理器,将表拖动到linq to sql 类,实体类就由Vs生成了 4.实例化Da ...
- checklistbox的使用
public class CheckListboxHelper { #region 为checklistbox绑定数据源 /// <summary> /// 为checklistbox绑定 ...
- Hadoop安装(2)安装hadoop 前的centos 设置
将虚拟机网络连接设为:Bridged 添加用户:hadoop,设置密码.关闭防火墙,selinux.暂且不关闭不需要的任务. 参照:http://www.cnblogs.com/xia520pi/ar ...
- RDLC报表系列(五) 简单的图表-柱状图
继续接上一篇的内容,本文主要是讲图标的内容,本文就是简单的图标,复杂的柱状图和折线图在下一文章中介绍. 数据源还是上文RDLC报表系列(四) 矩阵中的相同 1.还是继续使用demo2的文件
- SpringMVC中采用简洁的配置实现文件上传
文件上传我们一般会有两种策略,一种是通过IO流上传,还有一种是通过表单上传,其实这两种在客户端实现起来都是很简单的,在服务端处理会略有差别,个人感觉IO上传代码简单,但是也有很多硬伤,还是表单上传更合 ...
- (转)C#与C++之间类型的对应
C#与C++之间类型的对应 Windows Data Type .NET Data Type BOOL, BOOLEAN Boolean or Int32 BSTR String BYTE Byte ...
- JSON 小记
JSON是在web应用中频繁使用的一种数据结构,在使用过程中经常出现格式错误等等问题,如果能清晰的了解JSON的构成,那将会避免这些错误 英文好的可以查看原文: 地址:http://www.codep ...
- WebService到底是什么
WebService到底是什么 http://blog.csdn.net/wooshn/article/details/8069087 张孝祥WebService http://wenku.baid ...