C++之异常处理详解
发布时间:2023-04-10 10:22:00
程序中的错误分为编译时的错误和运行时的错误。编译时的错误主要是语法错误,比如:句尾没有加分号,括号不匹配,关键字错误等,这类错误比较容易修改,因为编译系统会指出错误在第几行,什么错误。而运行时的错误则不容易修改,因为其中的错误是不可预料的,或者可以预料但无法避免的,比如内存空间不够,或者在调用函数时,出现数组越界等错误。如果对于这些错误没有采取有效的防范措施,那么往往会得不到正确的运行结果,程序不正常终止或严重的会出现死机现象。我们把程序运行时的错误统称为异常,对异常处理称为异常处理。C++中所提供的异常处理机制结构清晰,在一定程度上可以保证程序的健壮性。
C++中处理异常的过程是这样的:在执行程序发生异常,可以不在本函数中处理,而是抛出一个错误信息,把它传递给上一级的函数来解决,上一级解决不了,再传给其上一级,由其上一级处理。如此逐级上传,直到最高一级还无法处理的话,运行系统会自动调用系统函数terminate,由它调用abort终止程序。这样的异常处理方法使得异常引发和处理机制分离,而不在同一个函数中处理。这使得底层函数只需要解决实际的任务,而不必过多考虑对异常的处理,而把异常处理的任务交给上一层函数去处理。
C++的异常处理机制有3部分组成:try(检查),throw(抛出),catch(捕获)。把需要检查的语句放在try模块中,检查语句发生错误,throw抛出异常,发出错误信息,由catch来捕获异常信息,并加以处理。一般throw抛出的异常要和catch所捕获的异常类型所匹配。异常处理的一般格式为:
try
{
被检查语句
throw 异常
}
catch(异常类型1)
{
进行异常处理的语句1
}
catch(异常类型2)
{
进行异常处理的语句2
}
...
下面我们用示例演示一下异常处理:
#include "stdafx.h"
#include <iostream>
template <typename T>
T Div(T x,T y)
{
if(y==0)
throw y;//抛出异常
return x/y;
}
int main()
{
int x=5,y=0;
double x1=5.5,y1=0.0;
try
{
//被检查的语句
std::cout<<x<<"/"<<y<<"="<<Div(x,y)<<std::endl;
std::cout<<x1<<"/"<<y1<<"="<<Div(x1,y1)<<std::endl;
}
catch(int)//异常类型
{
std::cout<<"除数为0,计算错误!"<<std::endl;//异常处理语句
}
catch(double)//异常类型
{
std::cout<<"除数为0.0,计算错误!"<<std::endl;//异常处理语句
}
return0;
}
结果:
看了上述的示例代码,也许有人会问,第二个双精度类型的除法计算也应该抛出异常才对啊,在实际的运行过程中并非如此,其实该双精度类型除法函数根本没有被执行过。以上程序的执行规程为:调用函数Div(x,y)时发生异常,由函数Div中的语句"throw y"抛出异常,并不在往下执行return x/y,接着catch捕获int类型的异常并处理异常,最后直接执行"return 0"。因此函数Div(x1,y1)和catch(double){}模块根本没有被执行。如果,我们把y的值改为1,则结果就变成为:
如果在执行try语句模块时,没有发生异常,则catch语句块不起作用,流程转到其后的语句继续执行。从上述两个结果中可知第一次throw抛出的int类型所以找到处理该类型的catch,而第二次是抛出double类型所找到的是处理double类型的catch。
下面对异常处理补充几点:(1)try和catch块中必须要用花括号括起来,即使花括号内只有一个语句也不能省略花括号;(2)try和catch必须成对出现,一个try_catch结果中只能有一个try块,但可以有多个catch块,以便与不同的异常信息匹配;(3)如果在catch块中没有指定异常信息的类型,而用删节号"...",则表示它可以捕获任何类型的异常信息;(4)如果throw不包括任何表达式,表示它把当前正在处理的异常信息再次抛出,传给其上一层的catch来处理;(5)C++中一旦抛出一个异常,如果程序没有任何的捕获,那么系统将会自动调用一个系统函数terminate,由它调用abort终止程序;
最后还是一样,我将用一个示例来总结一下今天所讲的内容(开发工具:vs2010):
#include "stdafx.h"
#include <iostream>
template <typename T>
T Div(T x,T y)
{
if(y==0)
throw y;//抛出异常
return x/y;
}
int main()
{
int x=5,y=1;
double x1=5.5,y1=0.0;
try
{
//被检查的语句
std::cout<<x<<"/"<<y<<"="<<Div(x,y)<<std::endl;
std::cout<<x1<<"/"<<y1<<"="<<Div(x1,y1)<<std::endl;
}
catch(...)//捕获任意类型异常
{
try
{
std::cout<<"任意类型异常!"<<std::endl;
throw;//抛出当前处理异常信息给上一层catch
}
catch(int)//异常类型
{
std::cout<<"除数为0,计算错误!"<<std::endl;//异常处理语句
}
catch(double)//异常类型
{
std::cout<<"除数为0.0,计算错误!"<<std::endl;//异常处理语句
}
}
return0;
}
结果:


猜你喜欢
- 我们通过一个完整的实例来实现课程信息管理功能的操作,包括查询、修改、删除课程信息的操作。为了简化实例,添加课程信息的操作直接在 SQL Se
- 昨天有朋友在公众号发消息说看不懂await,async执行流,其实看不懂太正常了,因为你没经过社会的毒打,没吃过牢饭就不知道自由有多重要,没
- 本文实例讲述了Java基于socket实现的客户端和服务端通信功能。分享给大家供大家参考,具体如下:以下代码参考马士兵的聊天项目,先运行Ch
- 导入thymeleaf<dependency> <groupId>org.springframework
- 从事过ASP.NET开发的可能都会接触到一些图表控件,比如OWC、ZendGraph等等,这些控件都有一个特点,那就是我们可以像操作.NET
- 和室友参加的互联网大赛要做一个 APP,涉及到用户的登录注册,于是上网找了许多资料,其中有阿里大于,网易云等等,阿里大于的客服给我说他们不支
- 项目代码:https://github.com/bruceq/supermarket项目结构:依赖关系:common:公共层,无依赖dao:
- 前言Java泛型这个特性是从JDK 1.5才开始加入的,因此为了兼容之前的版本,Java泛型的实现采取了“伪泛型”的策略,即Java在语法上
- web.xml文件配置创建好一个SpringMVC项目后,需要在需要在WB-INF文件夹下配置web.xml文件<?xml versi
- 上篇博客我们了解了请求参数的获取,那么获取到请求参数之后,需要对参数进行出来,然后进行数据响应。那么这篇博客我们就来了解 Controlle
- 目录背景问题解决思路其他问题小结背景关于个人,前段时间由于业务太忙,所以一直没有来得及思考并且沉淀点东西;同时组内一个个都在业务上能有自己的
- 所谓c#的委托就是说把函数当参数来传递。这个在js完全就用不着搞什么委托东西,直接转就是了。而对于C#来说则不是这样!一个函数,如果它的参数
- 网上关于如何切换,其实说的很明确,本文主要通过profile进行快速切换已实现在不同场合下,用不同的打包方式。jar到war修改步骤pom文
- 在官方的这篇文档中为大家介绍了如何使用Java开启Azure Windows虚拟机的诊断设置这篇文章呢,为大家介绍一下如何使用Java开启L
- 引言Random类是非常值得学习的一个类,所以我们今天一起学习一下Random这个类,对于模拟数据这个是随机类可是一个好东西,我们可以用这个
- 本文根据java开发人员在编码过程中容易忽视或经常出错的地方进行了整理,总结了十个比较常见的低级错误点,方便大家学习。1、不能用“==”比较
- 当数据库中存有大量数据的时候,用Cursor查询时要注意,有可能引发性能问题。数据库查询出来的Cursor都会由一个CursorWindow
- 前言在前面的文章中其实大家也已经看到我使用过collect(Collectors.toList()) 将数据最后汇总成一个 List 集合。
- 实现过滤请求有两种方式:一种就是用 * ,一种就是过滤器 * 相对来说比较专业,而过滤器虽然不专业但是也能完成基本的拦截请求要求。一、 *
- 步骤,如图所示:1.添加异步任务业务类package top.ytheng.demo.task;import java.util.concu