编译器能够保证代码的语法是正确的,但是对逻辑错误和运行时错误却无能为力,例如除数为 0、内存分配失败、数组越界等。这些错误如果放任不管,系统就会执行默认的操作,终止程序运行,也就是我们常说的程序崩溃(Crash)。

优秀的程序员能够从故障中恢复,或者提示用户发生了什么;不负责任的程序员放任不管,让程序崩溃。C++提供了异常机制,让我们能够捕获逻辑错误和运行时错误,并作出进一步的处理。

一个程序崩溃的例子:

#include <iostream>
using namespace std;
int main(){
string str = "c plus plus";
char ch1 = str[]; //下标越界,ch1为垃圾值
cout<<ch1<<endl;
char ch2 = str.at(); //下标越界,抛出异常
cout<<ch2<<endl;
return ;
}

运行代码,在控制台输出 ch1 的值后程序崩溃。下面我们来分析一下。

at() 是 string 类的一个成员函数,它会根据下标来返回字符串的一个字符。与“[ ]”不同,at() 会检查下标是否越界,如果越界就抛出一个异常(错误);而“[ ]”不做检查,不管下标是多少都会照常访问。

上面的代码中,下标 100 显然超出了字符串 str 的长度。由于第 6 行代码不会检查下标越界,虽然有逻辑错误,但是程序能够正常运行。而第 8 行代码则不同,at() 函数检测到下标越界会抛出一个异常(也就是报错),这个异常本应由程序员处理,但是我们在代码中并没有处理,所以系统只能执行默认的操作,终止程序执行。

捕获异常

在C++中,我们可以捕获上面的异常,避免程序崩溃。捕获异常的语法为:

try{
// 可能抛出异常的语句
}catch(异常类型){
// 处理异常的语句
}

try 和 catch 都是C++中的关键字,后跟语句块,不能省略“{ }”。try 中包含可能会抛出异常的语句,一旦有异常抛出就会被捕获。从“try”的意思可以看出,它只是“尝试”捕获异常,如果没有异常抛出,那就什么也不捕获。catch 用来处理 try 捕获到的异常;如果 try 没有捕获到异常,就不会执行 catch 中的语句。

修改上面的代码,加入捕获异常的语句:

#include <iostream>
using namespace std;
int main(){
string str = "c plus plus"; try{
char ch1 = str[];
cout<<ch1<<endl;
}catch(exception e){
cout<<"[1]out of bound!"<<endl;
}
try{
char ch2 = str.at();
cout<<ch2<<endl;
}catch(exception e){
cout<<"[2]out of bound!"<<endl;
}
return ;
}

可以看出,第一个 try 没有捕获到异常,输出了一个垃圾值。因为“[ ]”不会检查下标越界,不会抛出异常,所以即使有逻辑错误,try 什么也捕获不到。

第二个 try 捕获到了异常,并跳转到 catch,执行 catch 中的语句。需要说明的是,异常一旦抛出,会立即被捕获,而且不会再执行异常点后面的语句。本例中抛出异常的位置是第 15 行的 at() 函数,它后面的 cout 语句不会再被执行,也就看不到输出。

异常类型

所谓抛出异常,实际上是创建一份数据,这份数据包含了错误信息,程序员可以根据这些信息来判断到底出了什么问题,接下来该怎么处理。

异常既然是一份数据,那么就应该有数据类型。C++规定,异常类型可以是基本类型,也可以是标准库中类的类型,还可以是自定义类的类型。C++语言本身以及标准库中的函数抛出的异常,都是 exception 类或其子类的类型。也就是说,抛出异常时,会创建一个 exception 类或其子类的对象。

异常被捕获后,会和 catch 所能处理的类型对比,如果正好和 catch 类型匹配,或者是它的子类,那么就交给当前 catch 块处理。catch 后面的括号中给出的类型就是它所能处理的异常类型。上面例子中,catch 所能处理的异常类型是 exception,at() 函数抛出的类型是 out_of_range,out_of_range 是 exception 的子类,所以就交给这个 catch 块处理。

catch 后面的exception e可以分为两部分:exception 为异常类型,e 为 exception 类的对象。异常抛出时,系统会创建 out_of_range 对象,然后将该对象作为“实参”,像函数一样传递给“形参”e,这样,在 catch 块中就可以使用 e 了。

其实,一个 try 后面可以跟多个 catch,形式为:

try
{
//可能抛出异常的语句
}
catch (exception_type_1)
{
//处理异常的语句
}
catch (exception_type_2)
{
//处理异常的语句
}
// ……
catch (exception_type_n)
{
//处理异常的语句
}

异常被捕获时,先和 exception_type_1 作比较,如果异常类型是 exception_type_1 或其子类,那么执行当前 catch 中的代码;如果不是,再和 exception_type_2 作比较……依此类推,直到 exception_type_n。如果最终也没有找到匹配的类型,就只能交给系统处理,终止程序。

多个 catch 块的例子:

#include <iostream>
#include <exception>
#include <stdexcept>
using namespace std;
//自定义错误类型
class myType: public out_of_range{
public:
myType(const string& what_arg): out_of_range(what_arg){}
};
int main(){
string str = "c plus plus";
try{
char ch1 = str.at();
cout<<ch1<<endl;
}catch(myType){
cout<<"Error: myType!"<<endl;
}catch(out_of_range){
cout<<"Error: out_of_range!"<<endl;
}catch(exception){
cout<<"Error: exception!"<<endl;
}
return ;
}

try 捕获到异常后和第一个 catch 对比,由于此时异常类型为 out_of_range,myType 是 out_of_range 的子类,所以匹配失败;继续向下匹配,发现第二个 catch 合适,匹配结束;第三个 catch 不会被执行。

需要注意的是:catch 后面的括号中仅仅给出了异常类型,而没有所谓的“形参”,这是合法的。如果在 catch 中不需要使用错误信息,就可以省略“形参”。

C++学习39 异常处理入门(try和catch)的更多相关文章

  1. 22 C#中的异常处理入门 try catch throw

    软件运行过程中,如果出现了软件正常运行不应该出现的情况,软件就出现了异常.这时候我们需要去处理这些异常.或者让程序终止,避免出现更严重的错误.或者提示用户进行某些更改让程序可以继续运行下去. C#编程 ...

  2. Scala深入浅出实战经典-----002Scala函数定义、流程控制、异常处理入门实战

    002-Scala函数定义.流程控制.异常处理入门实战 Scala函数定义 语句结束无分号 定义无参函数 def 函数名称(参数名称:参数类型)[:Unit=]{ 函数体 } 老师的代码 我的实际代码 ...

  3. Netty学习——Thrift的入门使用

    Netty学习——Thrift的入门使用 希望你能够,了解并使用它.因为它是一个效率很高的框架 官网地址:http://thrift.apache.org/ 1.Thrift数据类型 一门技术如果需要 ...

  4. DBFlow框架的学习笔记之入门

    什么是DBFlow? dbflow是一款android高性的ORM数据库.可以使用在进行项目中有关数据库的操作.github下载源码 1.环境配置 先导入 apt plugin库到你的classpat ...

  5. 从零开始学习JAVA(入门基础)

    目录 博主从零开始学习JAVA(入门基础) 1.搭建JAVA开发环境 卸载JDK(未安装的请忽略) 安装JDK 2.编程语言中,何为编译型与解释型 编译型 解释型 3.第一个JAVA应用程序 4.JA ...

  6. 从零开始学习jQuery (一) 入门篇

    本系列文章导航 从零开始学习jQuery (一) 入门篇 一.摘要 本系列文章将带您进入jQuery的精彩世界, 其中有很多作者具体的使用经验和解决方案,  即使你会使用jQuery也能在阅读中发现些 ...

  7. python学习笔记--Django入门四 管理站点--二

    接上一节  python学习笔记--Django入门四 管理站点 设置字段可选 编辑Book模块在email字段上加上blank=True,指定email字段为可选,代码如下: class Autho ...

  8. WebSocket学习笔记——无痛入门

    WebSocket学习笔记——无痛入门 标签: websocket 2014-04-09 22:05 4987人阅读 评论(1) 收藏 举报  分类: 物联网学习笔记(37)  版权声明:本文为博主原 ...

  9. 腾讯QQ会员技术团队:人人都可以做深度学习应用:入门篇(下)

    四.经典入门demo:识别手写数字(MNIST) 常规的编程入门有"Hello world"程序,而深度学习的入门程序则是MNIST,一个识别28*28像素的图片中的手写数字的程序 ...

随机推荐

  1. 虚拟化之lxc

    LXC 中文名称就是 Linux 容器工具,容器可以提供轻量级的虚拟化,以便隔离进程和资源,使用 LXC 的优点就是不需要安装太多的软件包,使用过程也不会占用太多的资源,本文循序渐进地介绍LXC的建立 ...

  2. svn安装

    方法三.无法连接网络的情况(link链接) 1.从官网下载 Site-1.6.5.zip 2.解压Site-1.6.5.zip至${eclipse}PluginsSubclipse-1.6.5.zip ...

  3. Excel 导入并导出结果集

    1.controler代码: /// <summary> /// 导入预归类意见书 /// </summary> /// <param name="upload ...

  4. 车载凯立德导航地图更新以及DSA数据更新方法

    每年升级每次都去重新摸索,1年时间忘完了,遂决定把他写下来,我这就去实验,实验好了来补 第一步: 找最新的凯立德软件和地图版本号 方法:淘宝搜索, 例如:凯立德 2016,搜索结果会出现比如2016 ...

  5. sql字符串查找大小写敏感相关

    select * from table   where target_text like "3"; 等价于 select * from table   where target_t ...

  6. 使用原生js写ajax

    // 使用原生js 封装ajax // 兼容xhr对象 function createXHR(){ if(typeof XMLHttpRequest != "undefined") ...

  7. RMAN备份与恢复之spfile

    1.备份spfile 有关控制文件及参数文件备份的几种形式: 单独备份控制文件及参数文件 RMAN> backup current controlfile; 备份数据文件时包含控制文件 RMAN ...

  8. Web前端相关

    1)emmet2)prettify3)angularjs4)coffeescript5)bower (nodejs)6)requirejs

  9. 剑指offer系列23---字符串排列(不是很理解)

    [题目]输入一个字符串,按字典序打印出该字符串中字符的所有排列. 例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 结果请按字母顺 ...

  10. TCP/IP四层模型和OSI七层模型的概念

    转:http://blog.csdn.net/superjunjin/article/details/7841099/ TCP/IP四层模型 TCP/IP是一组协议的代名词,它还包括许多协议,组成了T ...