c++ primer plus 第15章友,异常和其他 15.3.10 异常何时会迷失方向

c++ primer plus 第15章友,异常和其他 15.3.10 异常何时会迷失方向

15.3.10 异常何时会迷失方向


15.3.10 异常何时会迷失方向

异常被引发后,在两种情况下,会导致问题。首先,如果它是在带异常规范的函数中引发的,则必须与规范列表中的某种异常匹配(在继承层次结构中,类类型与这个类及其派生类的对象匹配),否则称为意外异常(unexpected exception)。在默认情况下,这将导致程序异常终止(虽然 C++11摒弃了异常规范,但仍支持它,且有些现有的代码使用了它)。如果异常不是在函数中引发的(或者函数没有异常规范),则必须捕获它。如果没被捕获(在没有ty块或没有匹配的 catch块时,将出现这种情况),则异常被称为未捕获异常(umcaughtcxccption)。在默认情况下,这将导致程序异常终止。然而,可以修改程序对意外异常和未捕获异常的反应。下面来看如何修改,先从未捕获异常开始。
未捕获异常不会导致程序立刻异常终止。相反,程序将首先调用函数temminate()。在默认情况下,terminate()调用 abort()函数。可以指定 terminate()应调用的函数(而不是 abort())来修改 terminate( )的这种行为。为此,可调用 set_terminate()函数。set_terminate()和terminate()都是在头文件 exception 中声明的:

typedef void (*terminate handler)();
terminate_handler set_terminate(terminate_handler f)throw();//C++98
terminate_handler set_terminate (terminate_handler f)noexcept; //C++11
void terminate();// C++98
void terminate()noexcept;// C++11

其中的 typedef使 terminatc_handlcr成为这样一种类型的名称:指向没有参数和返回值的函数的指针。set_terminate()函数将不带任何参数且返回类型为void的函数的名称(地址)作为参数,并返回该函数的地址。如果调用了 set_terminate()函数多次,则 terminate( )将调用最后一次 set_terminate()调用设置的函数。来看一个例子。假设希望未捕获的异常导致程序打印一条消息,然后调用exit()函数,将退出状态值设置为5。首先,请包含头文件cxception。可以使用using编译指令、适当的 using 声明或 std ::限定符,来使其声明可用。

#include <exception>
using namespace std;

然后,设计一个完成上述两种操作所需的函数,其原型如下:

void myQuit()
{
cout <<"Terminating due to uncaught exception\n";
exit(5);
}

最后,在程序的开头,将终止操作指定为调用该函数。
set terminate(myQuit);现在,如果引发了一个异常且没有被捕获,程序将调用tenminate(),而后者将调用MyOuit()。接下来看意外异常。通过给函数指定异常规范,可以让函数的用户知道要捕获哪些异常。假设函数的原型如下:

double Argh(double,double)throw(out_of_bounds);

则可以这样使用该函数:

try{
x=Argh(a,b);
}
catch(out_of_bounds & ex)
...
}

知道应捕获哪些异常很有帮助,因为默认情况下,未捕获的异常将导致程序异常终止。
原则上,异常规范应包含函数调用的其他函数引发的异常。例如,如果Argh()调用了Duh()函数,而后者可能引发 retont 对象异常,则 Argh()和 Duh()的异常规范中都应包含 retort。除非自己编写所有的函数,并且特别仔细,否则无法保证上述工作都已正确完成。例如,可能使用的是老式商业库,而其中的函数没有异常规范。这表明应进一步探讨这样一点,即如果函数引发了其异常规范中没有的异常,情况将如何?这也表明异常规范机制处理起来比较麻烦,这也是C++11将其摒弃的原因之一。
在这种情况下,行为与未捕获的异常极其类似。如果发生意外异常,程序将调用 unexpected()函数(您没有想到是 umexpected()函数吧?谁也想不到!)。这个函数将调用temminate(),后者在默认情况下将调用abort()。正如有一个可用于修改 terminate()的行为的 set terminate( )数一样,也有一个可用于修改unexpected()的行为的 set_unexpected()函数。这些新函数也是在头文件 exception 中声明的:

typedef void (*unexpected handler)():
unexpected_handler set_unexpected(unexpected_handler f) throw();// C++98
unexpected_handler set_unexpected(unexpected_handler f) noexcept ;// C++11// C++98
void unexpected();
void unexpected()noexcept;//C+0x

然而,与提供给setterminate()的函数的行为相比,提供给set unexpected()的函数的行为受到更严格的限制。具体地说,unexpected_handler函数可以:
通过调用 terminate()(默认行为)、abort()或 exit( )来终止程序;
引发异常。
引发异常(第二种选择)的结果取决于unexpected_handler函数所引发的异常以及引发意外异常的函数的异常规范:
如果新引发的异常与原来的异常规范匹配,则程序将从那里开始进行正常处理,即寻找与新引发的异常匹配的catch块。基本上,这种方法将用预期的异常取代意外异常:
如果新引发的异常与原来的异常规范不匹配,且异常规范中没有包括std::bad_exception 类型,则程序将调用 terminate()。bad_exception是从exception派生而来的,其声明位于头文件 exception中;
如果新引发的异常与原来的异常规范不匹配,且原来的异常规范中包含了std::bad_exception 类型,则不匹配的异常将被 std::bad_exception 异常所取代。总之,如果要捕获所有的异常(不管是预期的异常还是意外异常),则可以这样做:首先确保异常头文件的声明可用:

#include <exception>using namespace std;

然后,设计一个替代函数,将意外异常转换为badexception异常,该函数的原型如下:

void myUnexpected()
throw std::bad exception();//or just throw;

仅使用 throw,而不指定异常将导致重新引发原来的异常。然而,如果异常规范中包含了这种类型则该异常将被bad exception 对象所取代。
接下来在程序的开始位置,将意外异常操作指定为调用该函数:

set unexpected(myUnexpected};

最后,将bad_exception类型包括在异常规范中,并添加如下catch块序列:

double Argh(double, double)throw(out_of_bounds, bad_exception);
...
try {
	x=Argh(a,b);
}
catch(out_of_bounds & ex)
{
...
}
catch(bad_exception & ex)
{
...
}

相关推荐

  1. 10 异常与断言

    2024-07-11 03:38:03       44 阅读
  2. 7 1 异常处理

    2024-07-11 03:38:03       51 阅读
  3. 15异常处理

    2024-07-11 03:38:03       53 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-11 03:38:03       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-11 03:38:03       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-11 03:38:03       58 阅读
  4. Python语言-面向对象

    2024-07-11 03:38:03       69 阅读

热门阅读

  1. Linux 安装 docker-compose

    2024-07-11 03:38:03       20 阅读
  2. PostgreSQL

    2024-07-11 03:38:03       20 阅读
  3. Perl词法切分器:文本解析的瑞士军刀

    2024-07-11 03:38:03       18 阅读
  4. 解决Spring Boot中的安全漏洞与防护策略

    2024-07-11 03:38:03       20 阅读
  5. 二、Python日志系统之watchDog监控日志

    2024-07-11 03:38:03       22 阅读
  6. 如何预防SQL注入

    2024-07-11 03:38:03       21 阅读
  7. 1、预处理

    2024-07-11 03:38:03       22 阅读
  8. Jmeter进阶-接口自动化

    2024-07-11 03:38:03       16 阅读