C++ 异常处理 catch(...)介绍

   2015-08-13 0
核心提示:catch(…)能够捕获多种数据类型的异常对象,所以它提供给程序员一种对异常 对象更好的控制手段,使开发的软件系统有很好的可靠性

如果要想使一个catch block能抓获多种数据类型的异常对象的话,怎么办?C++标准中定义了一种特殊的catch用法,那就是” catch(…)”。
感性认识

1、catch(…)到底是一个什么样的东东,先来个感性认识吧!
看例子先:

复制代码 代码如下:

 int main()
{
try
{
cout << "在 try block 中, 准备抛出一个异常." << endl;
//这里抛出一个异常(其中异常对象的数据类型是int,值为1)
throw 1;
}
//catch( int& value )
//注意这里catch语句
catch( …)
{
cout << "在 catch(…) block 中, 抛出的int类型的异常对象被处理" << endl;
}
}

2、哈哈!int类型的异常被catch(…)抓获了,再来另一个例子:
复制代码 代码如下:

 int main()
{
try
{
cout << "在 try block 中, 准备抛出一个异常." << endl;
//这里抛出一个异常(其中异常对象的数据类型是double,值为0.5)
throw 0.5;
}
//catch( double& value )
//注意这里catch语句
catch( …)
{
cout << "在 catch(…) block 中, double类型的异常对象也被处理" << endl;
}
}

3、同样,double类型的异常对象也被catch(…)块抓获了。是的,catch(..)能匹配成功所有的数据类型的异常对象,包括C++语言提 供所有的原生数据类型的异常对象,如int、double,还有char*、int*这样的指针类型,另外还有数组类型的异常对象。同时也包括所有自定义 的抽象数据类型。例程如下:
复制代码 代码如下:

 int main()
{
try
{
cout << "在 try block 中, 准备抛出一个异常." << endl;
//这里抛出一个异常(其中异常对象的数据类型是char*)
char* p=0;
throw p;
}
//catch( char* value )
//注意这里catch语句
catch( …)
{
cout << "在 catch(…) block 中, char*类型的异常对象也被处理" << endl;
}
}
int main()
{
try
{
cout << "在 try block 中, 准备抛出一个异常." << endl;
//这里抛出一个异常(其中异常对象的数据类型是int[])
int a[4];
throw a;
}
//catch( int value[] )
//注意这里catch语句
catch( …)
{
cout << "在 catch(…) block 中, int[]类型的异常对象也被处理" << endl;
}
}

4、对于抽象数据类型的异常对象。catch(…)同样有效,例程如下:
复制代码 代码如下:

 class MyException
{
public:
protected:
int code;
};
int main()
{
try
{
cout << "在 try block 中, 准备抛出一个异常." << endl;
//这里抛出一个异常(其中异常对象的数据类型是MyException)
throw MyException();
}
//catch(MyException& value )
//注意这里catch语句
catch( …)
{
cout << "在catch(…) block中, MyException类型的异常对象被处理" << endl;
}
}

对catch(…)有点迷糊?
1、究竟对catch(…)有什么迷糊呢?还是看例子先吧!
复制代码 代码如下:

void main()
{
int* p = 0;
try
{
// 注意:下面这条语句虽然不是throw语句,但它在执行时会导致系统
// 出现一个存储保护错误的异常(access violation exception)
*p = 13; // causes an access violation exception;
}
catch(...)
{
//catch(…)能抓获住上面的access violation exception异常吗?
cout << "在catch(…) block中" << endl;
}
}

请问上面的程序运行时会出现什么结果吗?catch(…)能抓获住系统中出现的access violation exception异常吗?朋友们!和我们的主人公阿愚一样,自己动手去测试一把!

结果又如何呢?实际上它有两种不同的运行结果,在window2000系统下用VC来测试运行这个小程序时,发现程序能输出"在catch(…) block中"的语句在屏幕上,也即catch(…) 能成功抓获住系统中出现的access violation exception异常,很厉害吧!但如果这个同样的程序在linux下用gcc编译后运行时,程序将会出现崩溃,并在屏幕上输出”segment fault”的错误信息。

主人公阿愚有点急了,也开始有点迷糊了,为什么?为什么?为什么同样一个程序在两种不同的系统上有不同的表现呢?其原因就是:对于这种由于硬件或操作 系统出现的系统异常(例如说被零除、内存存储控制异常、页错误等等)时,window2000系统有一个叫做结构化异常处理(Structured Exception Handling,SEH)的机制,这个东东太厉害了,它能和VC中的C++异常处理模型很好的结合上(实际上VC实现的C++异常处理模型很大程度上建 立在SEH机制之上的,或者说它是SEH的扩展,后面文章中会详细阐述并分析这个久富盛名的SEH,看看catch(…)是如何神奇接管住这种系统异常出 现后的程序控制流的,不过这都是后话)。而在linux系统下,系统异常是由信号处理编程方法来控制的(信号处理编程,signal processing progamming。在介绍unix和linux下如何编程的书籍中,都会有对信号处理编程详细的介绍,当然执着的主人公阿愚肯定对它也不会放过,会深 入到unix沿袭下来的信号处理编程内部的实现机制,并尝试完善改进它,使它也能够较好地和C++异常处理模型结合上)。

那么C++标准中对于这种同一个程序有不同的运行结果有何解释呢?这里需要注意的是,window2000系统下catch(…)能捕获住系统异常, 这完全是它自己的扩展。在C++标准中并没有要求到这一点,它只规定catch(…)必须能捕获程序中所有通过throw语句抛出的异常。因此上面的这个 程序在linux系统下的运行结果也完全是符合C++标准的。虽然大家也必须承认window2000系统下对C++异常处理模型的这种扩展确实是一个很 不错的完善,极大得提高了程序的安全性。

为什么要用catch(…)这个东东?
程序员朋友们也许会说,这还有问吗?这篇文章的一开始不就讲到了吗?catch(…)能够捕获多种数据类型的异常对象,所以它提供给程序员一种对异常 对象更好的控制手段,使开发的软件系统有很好的可靠性。因此一个比较有经验的程序员通常会这样组织编写它的代码模块,如下:

复制代码 代码如下:

 void Func()
{
try
{
// 这里的程序代码完成真正复杂的计算工作,这些代码在执行过程中
// 有可能抛出DataType1、DataType2和DataType3类型的异常对象。
}
catch(DataType1& d1)
{
}
catch(DataType2& d2)
{
}
catch(DataType3& d3)
{
}
// 注意上面try block中可能抛出的DataType1、DataType2和DataType3三
// 种类型的异常对象在前面都已经有对应的catch block来处理。但为什么
// 还要在最后再定义一个catch(…) block呢?这就是为了有更好的安全性和
// 可靠性,避免上面的try block抛出了其它未考虑到的异常对象时导致的程
// 序出现意外崩溃的严重后果,而且这在用VC开发的系统上更特别有效,因
// 为catch(…)能捕获系统出现的异常,而系统异常往往令程序员头痛了,现
// 在系统一般都比较复杂,而且由很多人共同开发,一不小心就会导致一个
// 指针变量指向了其它非法区域,结果意外灾难不幸发生了。catch(…)为这种
// 潜在的隐患提供了一种有效的补救措施。
catch(…)
{
}
}

还有,特别是VC程序员为了使开发的系统有更好的可靠性,往往在应用程序的入口函数中(如MFC框架的开发环境下 CXXXApp::InitInstance())和工作线程的入口函数中加上一个顶层的trycatch块,并且使用catch(…)来捕获一切所有的 异常,如下:
复制代码 代码如下:

 BOOL CXXXApp::InitInstance()
{
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return FALSE;
}
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// 注意这里有一个顶层的trycatch块,并且使用catch(…)来捕获一切所有的异常
try
{
CXXXDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
}
catch(…)
{
// dump出系统的一些重要信息,并通知管理员查找出现意外异常的原因。
// 同时想办法恢复系统,例如说重新启动应用程序等
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}

通过上面的例程和分析可以得出,由于catch(…)能够捕获所有数据类型的异常对象,所以在恰当的地方使用catch(…)确实可以使软件系统有着更 好的可靠性。这确实是大家使用catch(…)这个东东最好的理由。但不要误会的是,在C++异常处理模型中,不只有catch(…)方法能够捕获几乎所 有类型的异常对象.

 
标签: 异常 catch
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 《R语言数据挖掘》读书笔记:七、离群点(异常值)检测
    《R语言数据挖掘》读书笔记:七、离群点(异常值
    第七章、异常值检测(离群点挖掘)概述:        一般来说,异常值出现有各种原因,比如数据集因为数据来自不同的类、数据测量系统误差而收到损害。根据异常值的检测,异常值与原始数据集中的常规数据显著不同。开发了多种解决方案来检测他们,其中包括
    03-08
  • dart系列之:dart语言中的异常 dart新手的错误
    目录简介Exception和ErrorThrow和catchFinally总结简介Exception是程序中的异常情况,在JAVA中exception有checked Exception和unchecked Exception。那么在dart中的情况是不是一样的呢?一起来看看吧。Exception和ErrorDart中表示异常的类有两个,分别是Excep
    02-09
  • 线上服务异常的定位、处理与优化的探索 - 第三章 Java虚拟机
    线上服务异常的定位、处理与优化的探索 - 第三
    Java虚拟机 之所以引入关于JVM的篇章,是发现多数项目发生的线上问题很大的几率源自JVM调优配置不当引起。对JVM的内存模型、GC垃圾回收机制、调优方式有一个系统化的了解后,可以快速处理或避免以下两类问题:以最合适的JVM参数配置生产环境项目,可以大大减
    02-09
  • Python+Sklearn实现异常检测
    目录离群检测 与 新奇检测Sklearn 中支持的方法孤立森林 IsolationForestLocal Outlier FactorOneClassSVMElliptic Envelope离群检测 与 新奇检测很多应用场景都需要能够确定样本是否属于与现有的分布,或者应该被视为不同的分布。离群检测(Outlier detectio
  • Python异常与错误处理详细讲解 python的异常
    基础知识优先使用异常捕获LBYL(look before you leap): 在执行一个可能出错的操作时,先做一些关键的条件判断,仅当满足条件时才进行操作。EAFP(eaiser to ask for forgiveness than permission): 不做事前检查,直接执行操作。后者更优: 代码简洁,效率更高
  • 由ASP.NET Core根据路径下载文件异常引发的探究
    前言    最近在开发新的项目,使用的是ASP.NET Core6.0版本的框架。由于项目中存在文件下载功能,没有使用类似MinIO或OSS之类的分布式文件系统,而是下载本地文件,也就是根据本地文件路径进行下载。这其中遇到了一个问题,是关于如何提供文件路径的,通
    02-09
  • delphi 异常处理机制
    一、异常的来源。在Delphi的应用程序中,下列的情况都比较有可能产生异常。(1)文件处理(2)内存分配(3)Windows资源(4)运行时创建对象和窗体(5)硬件和操作系统冲突二、异常的处理。(1)try…except…end;在try体内的代码发生异常时,系统将转向excep
    02-09
  • Try::Tiny Perl 异常的处理
    Perl 没有内置的异常处理机制,所以最合适的方法就是使用Try::Tiny 模块。虽然CPAN中处理异常的模块很多,但是这个模块最为轻巧,使用起来也没有过多的依赖关系。语法:use autodie;use Try::Tiny;# handle errors with a catch handlertry {die "foo";} catch
    02-09
  • Matlab IQR准则剔除异常值
    Matlab IQR准则剔除异常值
    时间序列分析中,要先进行数据的预处理工作,也即异常值的剔除和插补。先介绍异常值的剔除。异常值的剔除方法有很多种,在此实现很多论文中提到过的所谓的IQR准则。理论基础:                                                   
    02-09
  • 【R笔记】使用R语言进行异常检测 r语言检验
    【R笔记】使用R语言进行异常检测 r语言检验
    本文转载自cador《使用R语言进行异常检测》本文结合R语言,展示了异常检测的案例,主要内容如下:(1)单变量的异常检测(2)使用LOF(local outlier factor,局部异常因子)进行异常检测(3)通过聚类进行异常检测(4)对时间序列进行异常检测一、单变量异常
    02-09
点击排行