C++ 异常的详解

程序有时会遇到运行阶段错误,导致程序无法正常执行下去。c++异常为处理这种情况提供了一种功能强大的而灵活的工具。异常是相对比较新的C++功能,有些老编译器可能没有实现。另外,有些编译器默认关闭这种特性,我们可能需要使用编译器选项来启用它。

一、异常机制的使用 

异常提供了将控制程序的一个部分传递到另一部分的途径。对异常的处理有3个组成部分:

引发异常

示例代码:

#include "stdafx.h"
#include <iostream>
double hmean(double a, double b);
int main()
{   double x, y, z; std::cout << "Enter two numbers: "; while (std::cin >> x >> y) {    try {   z = hmean(x, y);   }   catch(const char *s ){  std::cout << s << std::endl;    std::cout << " Enter a new pair of numbers: ";  continue;   }   std::cout << "Harmonic mean of " << x << " and " << y << " is " << z << std::endl;  std::cout << "Enter next set of numbers <q to quit>: ";   }   std::cout << "Bye! \n"; system("pause");  return 0;
}   double hmean(double a, double b) {  if (a == -b) {    throw "bad hmean() arguments a= -b not allowed"; }   return 2.0 *a*b / (a + b);
}   Enter two numbers: 3 6
Harmonic mean of 3 and 6 is 4
Enter next set of numbers <q to quit>: 10 -10
bad hmean() arguments a= -b not allowed    Enter a new pair of numbers: q
Bye!
请按任意键继续. . .

程序说明:

try块:

try   {   z = hmean(x, y);   }

引发异常的代码:

if (a == -b) { throw "bad hmean() arguments a= -b not allowed"; }

执行throw语句类似于执行返回语句,因为他也将终止函数的执行;但throw不是讲控制权返回给调用程序,而是导致程序沿函数调用序列后退,知道找到包含try块的函数。

处理程序(或catch块):

catch(const char *s ){    std::cout << s << std::endl;    std::cout << " Enter a new pair of numbers: ";  continue;   }

二、将对象用作异常类型 

通常,引发异常的函数将传递一个对象。这样做的重要优点之一是,可以使用不同的异常类型来区分不同的函数在不同情况下引发的异常。另外,对象可以携带信息,程序员可以根据这些信息来确定引发异常的原因。同时,catch块可以根据这些信息来决定采取什么样的措施。

示例:

exc_mean.h

#include "stdafx.h"
#include <iostream>   class bad_hmean
{
private:    double v1;  double v2;
public :    bad_hmean(double a = 0, double b = 0) :v1(a), v2(b) {}    void mesg();
};
inline void bad_hmean::mesg()
{   std::cout << "hmean ( " << v1 << " ," << v2 << ") ;"    << "invalid argumnents: a =-b \n";
}   class bad_gmean
{
public :    double v1;  double v2;  bad_gmean(double a = 0, double b = 0) :v1(a), v2(b) {}    const char * mesg();
};
inline const char* bad_gmean::mesg() {  return "gmean() arguments shoud be >=0 \n";
}

测试代码:

#include "stdafx.h"
#include <iostream>
#include <cmath>
#include "exc_mean.h" double hmean(double a, double b);
double gmean(double a, double b);   int main()
{   using std::cout;    using std::cin; using std::endl;    double x, y, z; 1 >> 2;   cout << "Enter two numbers ";   while (cin >> x >> y)   {   try {   z = hmean(x, y);   cout << "Harmonic mean of " << x << " and " << y << " is " << z << endl;    cout << " Geometric mean of " << x << " and " << y << " is " << gmean(x, y) << endl;    cout << " Enter next set of numbers <q to quit >:";   }   catch (bad_hmean & bg)  {   bg.mesg();  cout << "Try again. \n";    continue;   }   catch (bad_gmean & hg)  {   cout << hg.mesg();    cout << "Value used: " << hg.v1 << " ," << hg.v2 << endl; cout << "Sorry, you don't get to play any more .\n ";  break;  }   }   cout << " Bye! \n"; system("pause");  return 0;   return 0;
}   double hmean(double a, double b) {  if (a == -b)  throw bad_hmean(a, b);  return 2.0 * a*b / (a + b);
}
double gmean(double a, double b) {  if (a < 0 || b < 0) throw bad_gmean(a, b);    return std::sqrt(a * b);
}   输出结果:
Enter two numbers 4 12
Harmonic mean of 4 and 12 is 6  Geometric mean of 4 and 12 is 6.9282    Enter next set of numbers <q to quit >:5 -5
hmean ( 5 ,-5) ;invalid argumnents: a =-b
Try again.
5 -2
Harmonic mean of 5 and -2 is -6.66667
gmean() arguments shoud be >=0
Value used: 5 ,-2
Sorry, you don't get to play any more .    Bye!
请按任意键继续. . .

三、异常规范 

异常规范是C++98的一项功能,但c++11将其摒弃了。这意味着c++11仍然处于标准之中,但以后可能会从标准中剔除,因此不建议使用它。

异常规范示例:

double harm(double a ) throw(bad_thing);//可能会抛出 bad_thing异常
double marm(double ) throw() ;//不抛出异常

异常规范的作用:

1、告诉用户可能需要使用try块,然而这项功能也可使用注释轻松完成。

2、让编译器添加执行运行阶段检查代码,检查是否违反了异常规范,然而这很难检查,例如marm可能不会引发异常,但它可能调用一个函数,而这个函数调用另一个函数引发了异常

总之最好不要使用这项功能,c++11也建议忽略异常规范

然而c++11确实支持一种特殊的异常规范,可使用关键字noexcept

例如

double marm() noexcept;

四、栈解退 

假设函数由于异常(而不是由于返回)而终止,则程序也将释放栈中的内存,但不会师范栈的第一个返回地址后停止,而是继续释放栈,直到找到一个位于Try块的返回地址。随后,控制权将转到块尾的异常处理程序,而不是函数调用后面的第一条语句。这个过程叫做栈解退。

五、exception类 

较新的C++编译器将异常合并到语言中,例如,为支持该语言,exception头文件(以前为exception.h 或except.h)定义了 exception类,c++可以把它用作其他异常类的基类。

头文件 exceptionhe 和 stdexcept 定义了一些常用的异常类

有:logic_error、runtime_error、domain_error 等

六、意外异常与未捕获异常处理 

异常引发后,在两种情况下,会导致问题。首先,如果它是在带异常规范的函数中引发的,则必须与规范列表的某种异常匹配(在继承层次机构中,类类型与这个类与其派生的对象匹配),否则成为意外异常。在默认情况下,这将导致程序异常终止(虽然C++11摒弃了异常规范,但仍支持它,且有些现有代码使用了它)如果异常不是在函数中引发的(或者函数没有异常规范),则必须捕获它,如果没有捕获(在没有try块或没有匹配的catch块时,将出现这种情况),则异常被称未捕获异常。这将导致程序异常终止。然而可以修改程序对意外异常和为捕获异常的反应。

未捕获异常: 

未捕获异常不会导致程序立即异常中终止,相反,程序将首先调用函数terminate()。在默认情况下terminate()调用abort()函数。可以指定terminate()应调用的函数(而不是abort())来修改terminate()的这种行为。为此,可调用set_terminate()函数。set_terminate()和terminate()都是在头文件exception中声明的:

typedef void (*terminate_handle)() ;
terminate_handle set_terminate(terminate_handle f) throw();//c++ 98
terminate_handle set_terinate(terminate_handle f) noexcept; //c++11
void teminate(); //c++98
void teminate() noexcept ; //c++11

示例:

void myQuit()
{   std::cout << "Terminating due to uncaught exception \n";    system("pause");
}   在程序开始时执行:
set_terminate(myQuit);

意外异常 

如果发生意外异常,程序将调用unexcepted()函数,这个函数将调用teminate(),后者默认滴啊用abort()。和set_terminate()函数一样,也有一个可用于修改unexcepted()的行为的set_unexpeceted()函数。这些函数也是在头文件exception中声明的:

typedef void (* unexpected_handle)();
unexpected_handle set_unexpected(unexpected_handle f) throw();//c++98
unexpected_handle set_unexpected(unexpected_handle f) noexpect;//c++11
void unexpected(); c++ 98
void unexpected() noexcept ;//c+ 0x

使用如下:

void myUnexpected() {    throw std::bad_exception(); // or just throw ;
}
在程序开始时:<br>set_unexpected(myUnexpected);

我在vs 2015下测试,并未实现这种功能,必须显示调用terminate() 和 unexpected();

它,

不仅仅是一个码

扫码关注

C++资源免费送

C++ 异常的详细介绍相关推荐

  1. android os被删除怎么办,手机系统应用误删了怎么办 如何修复手机异常【详细介绍】...

    手机系统应用误删了怎么办? 应用在面向对象上通常分为个人用户应用(面向个人消费者)与企业级应用(面向企业),在移动端系统分类上主要包括iOSApp(如:同步推等)和Android Apk(如:AirD ...

  2. 什么是异常?异常的详细介绍

    异常 什么是异常?(看代码) public class Exception{public static void main(String[] args){int num1 = 10;int num2 ...

  3. [ARM异常]-ARMV8的异步异常(中断)详细介绍

    快速链接: .

  4. 深入浅出详细介绍Java异常,让你茅塞顿开般的感觉

    零基础学习之Java异常 概述 基本介绍 Error 代码示例 Exception 代码示例 异常的处理 throw 代码示例 throws 代码示例 try-catch 代码示例 finally块 ...

  5. C++11 unordered_map详细介绍

    整理的算法模板合集: ACM模板 目录: 1.介绍 1.1 特性 2. 模版 2.1 迭代器 3. 功能函数 3.1 构造函数 3.2 容量操作 3.2.1 size 3.2.2 empty 3.3 ...

  6. Iptables防火墙详细介绍与实战增强服务器安全

    Iptables防火墙详细介绍与实战增强服务器安全 一:Iptables的概述及应用 iptables概述: netfilter/iptables : IP信息包过滤系统,它实际上由两个组件netfi ...

  7. hibernate主键详细介绍

    hibernate主键详细介绍 /** * * @author liuguangyi * @content ejb3注解的API定义在javax.persistence.*包里面. * * 注释说明: ...

  8. python流程控制语句-Python中流程控制语句的详细介绍

    除了刚才介绍的while语句之外,Python也从其他语言借鉴了其他流程控制语句,并做了相应改变.Python中流程控制语句的详细介绍 4.1 ifStatements 或许最广为人知的语句就是if语 ...

  9. Nacos注册中心的部署与用法详细介绍

    一.什么是注册中心: 我们知道微服务彼此间独立部署.具有清晰的边界,服务间通过远程调用来构建复杂的业务功能.而服务册中心在微服务项目中扮演着非常重要的角色,那么注册中心又是什么,使用服务注册中心可以解 ...

最新文章

  1. 习题4-3 求分数序列前N项和 (15 分)
  2. 几种优化方法的Matlab实现
  3. php+mysql+pdo连接数据库
  4. 《移动项目实践》实验报告——Android调试与上线
  5. 1037. 在霍格沃茨找零钱(20)
  6. 阿里云java mysql环境_阿里云搭建centos java mysql nginx环境
  7. windows平台下subversion服务器端配置
  8. canon l11121e驱动_佳能L11121e驱动官方下载-佳能Canon L11121e打印机驱动4.8.0.16 官方版-东坡下载...
  9. Mac上使用中文Beamer添加各种格式的图片
  10. 第一次使用并配置Hibernate
  11. thinkphp __hash__
  12. ue 新建html,第四课 开发uehtml官网响应式静态页面(示例代码)
  13. 如何卸载新版Edge并禁用自动更新
  14. Excel 文件格式解析
  15. 幼儿园案例经验迁移_幼儿园故事教学的实施策略
  16. 移动办公APP的开发费用和开发流程开发流程
  17. JAVA中盒子鱼与盒子的间隙,盒子鱼英语 - boxfish智能英语学习,全年龄段英语小班制...
  18. 1000瓶药水,只有一瓶是有毒的,如何使用最少的小白鼠测出那瓶是毒药?
  19. 正整数 n 分解成若干个互不相同的自然数的和,且使这些自然数的乘积最大
  20. 一个程序员的晋升之路

热门文章

  1. 多维柔性作业调用_摆脱困境:从预定作业中调用安全方法
  2. java 可变参数方法_Java方法中的参数太多,第7部分:可变状态
  3. servlet 异常处理_Servlet异常和错误处理示例教程
  4. 使用Spring开发Java RESTful Web服务的7个理由
  5. 如何使用JPA和Hibernate映射JSON集合
  6. java安全级别过高_Java应该是更高级别还是更低级别?
  7. swingworker_使用SwingWorker的Java Swing中的多线程
  8. 15分钟内使用Twilio和Stormpath在Spring Boot中进行身份管理
  9. 减少Java垃圾收集开销的5条提示
  10. spring.jpa配置_使用JPA和Spring 3.1进行事务配置