C++异常捕捉与处理的深入讲解

前言

在阅读别人开发的项目中,也许你会经常看到了多处使用异常的代码,也许你也很少遇见使用异常处理的代码。那在什么时候该使用异常,又在什么时候不该使用异常呢?在学习完异常基本概念和语法之后,后面会有讲解。

(1)异常抛出和捕捉语句

//1.抛出异常
throw 异常对象

//2.异常捕捉
try{
 可能会发生异常的代码
}catch(异常对象){
 异常处理代码
}
  • throw子句:throw 子句用于抛出异常,被抛出的异常可以是C++的内置类型(例如: throw int(1);),也可以是自定义类型。
  • try区段:这个区段中包含了可能发生异常的代码,在发生了异常之后,需要通过throw抛出。
  • catch子句:每个catch子句都代表着一种异常的处理。catch子句用于处理特定类型的异常。catch块的参数推荐采用地址传递而不是值传递,不仅可以提高效率,还可以利用对象的多态性。

(2)异常的处理规则

  • throw抛出的异常类型与catch抓取的异常类型要一致;
  • throw抛出的异常类型可以是子类对象,catch可以是父类对象;
  • catch块的参数推荐采用地址传递而不是值传递,不仅可以提高效率,还可以利用对象的多态性。另外,派生类的异常捕获要放到父类异常扑获的前面,否则,派生类的异常无法被扑获;
  • 如果使用catch参数中,使用基类捕获派生类对象,一定要使用传递引用的方式,例如catch (exception &e);
  • 异常是通过抛出对象而引发的,该对象的类型决定了应该激活哪个处理代码;
  • 被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那一个;
  • 在try的语句块内声明的变量在外部是不可以访问的,即使是在catch子句内也不可以访问;
  • 栈展开会沿着嵌套函数的调用链不断查找,直到找到了已抛出的异常匹配的catch子句。如果抛出的异常一直没有函数捕获(catch),则会一直上传到c++运行系统那里,导致整个程序的终止。

(3)实例

实例1:抛出自定义类型异常。

class Data
{
public:
 Data() {}
};

void fun(int n)
{
 if(n==0)
  throw 0;//抛异常 int异常
 if(n==1)
  throw "error"; //抛字符串异常
 if(n==2)
 {
  Data data;
  throw data;
 }
 if(n>3)
 {
  throw 1.0;
 }
}

int main()
{
 try {
  fun(6);//当异常发生fun里面,fun以下代码就不会再执行,调到catch处执行异常处理代码,后继续执行catch以外的代码。当throw抛出异常后,没有catch捕捉,则整个程序会退出,不会执行整个程序的以下代码
  cout<<"*************"<<endl;
 }catch (int i) {
  cout<<i<<endl;
 }catch (const char *ptr)
 {
  cout<<ptr<<endl;
 }catch(Data &d)
 {
  cout<<"data"<<endl;
 }catch(...)//抓取 前面异常以外的所有其他异常
 {
  cout<<"all"<<endl;
 }
 return 0;
}

实例2:标准出错类抛出和捕捉异常。

#include <iostream>
using namespace std;

int main()
{
 try {
  char* p = new char[0x7fffffff]; //抛出异常
 }
 catch (exception &e){
  cout << e.what() << endl; //捕获异常,然后程序结束
 }
 return 0;
}

输出结果:

当使用new进行开空间时,申请内存失败,系统就会抛出异常,不用用户自定义异常类型,此时捕获到异常时,就可告诉使用者是哪里的错误,便于修改。

实例3:继承标准出错类的派生类的异常抛出和捕捉。

#include <iostream>
#include <exception>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
class FileException :public exception
{
public:
 FileException(string msg) {
  this->exStr = msg;
 }
 virtual const char*what() const noexcept//声明这个函数不能再抛异常
 {
   return this->exStr.c_str();
 }
protected:
 string exStr;
};

void fun()
{
 int fd = ::open("./open.txt",O_RDWR);

 if(fd<0)
 {
  FileException openFail("open fail"); //创建异常对象
  throw openFail;//抛异常
 }
}

int main( )
{
 try {
  fun();
 } catch (exception &e) {//一般需要使用引用
  cout<<e.what()<<endl;
 }
 cout<<"end"<<endl;
 return 0;
}

当文件不存在时,输出结果:

如果在Linux上运行,上述代码需要根据环境修改:

98标准写法

~FileException()throw(){}//必须要
virtual const char*what() const throw()//声明这个函数不能再抛异常
{
  return this->exStr.c_str();
 }
 //编译
g++ main.cpp

2011标准写法

~FileException()noexcept{}//必须要
virtual const char*what() const noexcept//声明这个函数不能再抛异常
{
  return this->exStr.c_str();
}
 //编译
g++ main.cpp -std=c++11 指定用c++11标准编译

(4)总结

1. 使用异常处理的优点:

传统错误处理技术,检查到一个错误,只会返回退出码或者终止程序等等,我们只知道有错误,但不能更清楚知道是哪种错误。使用异常,把错误和处理分开来,由库函数抛出异常,由调用者捕获这个异常,调用者就可以知道程序函数库调用出现的错误是什么错误,并去处理,而是否终止程序就把握在调用者手里了。
2. 使用异常的缺点:

如果使用异常,光凭查看代码是很难评估程序的控制流:函数返回点可能在你意料之外,这就导致了代码管理和调试的困难。启动异常使得生成的二进制文件体积变大,延长了编译时间,还可能会增加地址空间的压力。
C++没有垃圾回收机制,资源需要自己管理。有了异常非常容易导致内存泄漏、死锁等异常安全问题。 这个需要使用RAII来处理资源的管理问题。学习成本较高。
C++标准库的异常体系定义得不好,导致大家各自定义各自的异常体系,非常的混乱。
3. 什么时候使用异常?

建议:除非已有的项目或底层库中使用了异常,要不然尽量不要使用异常,虽然提供了方便,但是开销也大。
4. 程序所有的异常都可以catch到吗?

并非如此,只有发生异常,并且又抛出异常的情况才能被catch到。例如,数组下标访问越界的情况,系统是不会自身抛出异常的,所以我们无论怎么catch都是无效的;在这种情况,我们需要自定义抛出类型,判断数组下标是否越界,然后再根据自身需要throw自定义异常对象,这样才可以catch到异常,并进行进一步处理。

到此这篇关于C++异常捕捉与处理的文章就介绍到这了,更多相关C++异常捕捉与处理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++之异常处理详解

    程序中的错误分为编译时的错误和运行时的错误.编译时的错误主要是语法错误,比如:句尾没有加分号,括号不匹配,关键字错误等,这类错误比较容易修改,因为编译系统会指出错误在第几行,什么错误.而运行时的错误则不容易修改,因为其中的错误是不可预料的,或者可以预料但无法避免的,比如内存空间不够,或者在调用函数时,出现数组越界等错误.如果对于这些错误没有采取有效的防范措施,那么往往会得不到正确的运行结果,程序不正常终止或严重的会出现死机现象.我们把程序运行时的错误统称为异常,对异常处理称为异常处理.C++中所

  • C++异常处理 try,catch,throw,finally的用法

    写在前面 所谓异常处理,即让一个程序运行时遇到自己无法处理的错误时抛出一个异常,希望调用者可以发现处理问题. 异常处理的基本思想是简化程序的错误代码,为程序键壮性提供一个标准检测机制. 也许我们已经使用过异常,但是你习惯使用异常了吗? 现在很多软件都是n*365*24小时运行,软件的健壮性至关重要. 内容导读 本文包括2个大的异常实现概念:C++的标准异常和SEH异常. C++标准异常: 也许你很高兴看到错误之后的Heap/Stack中对象被释放,可是如果没有呢? 又或者试想一下一个能解决的错误

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

    如果要想使一个catch block能抓获多种数据类型的异常对象的话,怎么办?C++标准中定义了一种特殊的catch用法,那就是" catch(-)". 感性认识 1.catch(-)到底是一个什么样的东东,先来个感性认识吧!看例子先: 复制代码 代码如下: int main() { try { cout << "在 try block 中, 准备抛出一个异常." << endl; //这里抛出一个异常(其中异常对象的数据类型是int,值为1

  • C++中的异常处理机制详解

    异常处理 增强错误恢复能力是提高代码健壮性的最有力的途径之一,C语言中采用的错误处理方法被认为是紧耦合的,函数的使用者必须在非常靠近函数调用的地方编写错误处理代码,这样会使得其变得笨拙和难以使用.C++中引入了异常处理机制,这是C++的主要特征之一,是考虑问题和处理错误的一种更好的方式.使用错误处理可以带来一些优点,如下: 错误处理代码的编写不再冗长乏味,并且不再和正常的代码混合在一起,程序员只需要编写希望产生的代码,然后在后面某个单独的区段里编写处理错误的嗲吗.多次调用同一个函数,则只需要某个

  • 举例说明自定义C++异常处理的实例

    举例说明自定义C++异常处理的实例 例1:自定义一个继承自excepton的异常类myException C++标准中,定义在<stdexcept>中的任何异常类都派生自exception Class,本例也只是简单地由exception继承,在try段抛出一个异常并捕捉.代码如下: /*++ test.cpp version:1.0 decript:define a exception class named myException derived from base class excep

  • c++异常处理机制示例及详细讲解

    这两天我写了一个测试c++异常处理机制的例子,感觉有很好的示范作用,在此贴出来,给c++异常处理的初学者入门.本文后附有c++异常的知识普及,有兴趣者也可以看看. 下面的代码直接贴到你的console工程中,可以运行调试看看效果,并分析c++的异常机制. 复制代码 代码如下: #include "stdafx.h" #include<stdlib.h> #include<crtdbg.h> #include <iostream> // 内存泄露检测机

  • 了解C++编程中指定的异常和未经处理的异常

    noexcept C++11:指定函数是否可能会引发异常. 语法 ReturnType FunctionName(params) noexcept; ReturnType FunctionName(params) noexcept(noexcept(expression); 参数 表达式 计算结果是 True 或 False 的常量表达式.无条件版本相当于 noexcept(true). 备注 noexcept(及其同义词 noecept(true))指定函数绝不会引发异常,或允许从异常直接或间

  • C++编程异常处理中try和throw以及catch语句的用法

    若要在 C++ 中实现异常处理,你可以使用 try.throw 和 catch 表达式. 首先,使用 try 块将可能引发异常的一个或多个语句封闭起来. throw 表达式发出信号,异常条件(通常是错误)已在 try 块中发生.你可以使用任何类型的对象作为 throw 表达式的操作数.该对象一般用于传达有关错误的信息.大多数情况下,建议你使用 std::exception 类或标准库中定义的派生类之一.如果其中的类不合适,建议你从 std::exception 派生自己的异常类. 若要处理可能引

  • C++中异常处理的基本思想及throw语句抛出异常的使用

    异常处理基本思想 C++的异常处理的基本思想大致可以概括为传统错误处理机制.通过函数返回值来处理错误. 1)C++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理.上层调用者可以再适当的位置设计对不同类型异常的处理. 2)异常是专门针对抽象编程中的一系列错误处理的,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法进行跳跃,但错误处理的特征却是遇到错误信息就想要转到若干级之上进行重新尝试,如图 3)异常超

  • C++的try块与异常处理及调试技术实例解析

    本文以示例形式简述了C++ try块的异常处理与调试技术,有助于读者复习并加深对try块的了解. 一.格式: 抛出异常throw 异常类型例如throw runtime_error("Data must refer to same ISBN"); try{ program-statements }catch(exception-specifier) { handler-statement; }catch(exception-specifier) { handler-statement;

随机推荐