C++异常处理机制

C++中可能出现的两种异常情况

  • 语法错误,即程序出现了错误的语句、函数结构和类,致使编译无法通过。一般编译器的报错机制就可以解决这类问题。
  • 运行时发生的错误,这一般与算法有关。C++异常处理机制就可以有效地处理这些问题。

C++异常处理机制介绍

C++异常处理机制主要使用try,throw,catch三大关键字。 try-catch语句形式如下:

require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
puts markdown.to_html
try
{ 
          //在这里写可能抛出异常的语句; 
} 
catch(Exception1& ex) // 捕获类型为Exception1的异常 
{ 
          //处理1
} 
catch(Exception2& ex) // 捕获类型为Exception2的异常 
{ 
         //处理2
} 
catch(...)    // 三个点表示捕获所有类型的异常
{ 
}

如果在try语句里面发现了异常,并且抛出了该异常,那么该异常将按照顺序与try语句块后面的多个catch语句中异常的类型逐个匹配,若是类型相同则该异常将会被对应的catch语句捕获,并且后续的catch语句也不会再执行判断(一个异常只能被一个catch语句捕获,除非该异常被捕获后又被重新抛出,这个后面会讲到,这里不考虑这种情况)。若所有的catch语句都无法捕获该异常,那么将会导致程序中止运行的情况。

那么如何才能抛出异常呢?答案很简单,就是用:

throw 表达式;
    //这里的表达式其实就是某些异常类型的实例化对象
    //可以是一个内置变量(如int、float类型的变量),也可以是自己定义的或者标准库中的异常类的对象

举个例子,如果我想抛出标准库中的一个runtime_error异常,可以这样写:

throw runtime_error("messages");
     //这里的“message"是初始化用的

下面举个完整的例子来说明异常的处理:

#include <iostream>
#include <stdexcept>//include standard exception classes
using namespace std;

int div(int num1, int num2)
{
    if(num2 == 0)
        throw runtime_error("Divisor cannot be zero");

    return num1/num2;
}

int main()
{
    int num1,num2;
    cin>>num2>>num2;//read two integers
    try
    {
        int res = div(num1,num2);
        cout<<num1<<"/"<<num2<<"is"<<res<<endl;
    }
    catch(runtime_error& ex)
    {
        cout<<ex.what()<<endl;
        //what方法返回初始化时作为参数传进去的字符串
    }

这里需要注意第一点是:如果输入的num2是0,那么div()函数将会抛出异常,同时try语块中共在 int res = div(num1,num2); 语句后面的代码将会被直接跳过而不会被执行。第二点是catch语句用引用接受参数,这样做的好处就是:不用拷贝参数,提高了传参的效率,同时还可以利用多态性(可以在一定程度上处理更大范围的异常类型)。

在上面提到,异常被捕获之后可以被重新抛出,之所以要这样做的原因是:有可能单个catch不能完全处理一个异常,此时在进行了一些处理工作之后,需要将异常重新抛出,由函数调用链中更上层的函数来处理。重新抛出的具体实现为throw;,throw后不跟表达式或类型。

异常的接口声明

这部分网上有人已做了总结,下同,引用如下:

为了加强程序的可读性,使函数的用户能够方便地知道所使用的函数会抛出哪些异常,可以在函数的声明中列出这个函数可能抛出的所有异常类型,例如:void fun() throw( A,B,C,D);这表明函数fun()可能并且只可能抛出类型(A,B,C,D)及其子类型的异常。
如果在函数的声明中没有包括异常的接口声明,则此函数可以抛出任何类型的异常,例如:void fun();
一个不会抛出任何类型异常的函数可以进行如下形式的声明:void fun() thow();

原文链接:http://www.cnblogs.com/stewill/articles/2737595.html

异常处理中需要注意的问题

(1).一般在异常抛出后资源可以正常被释放,但注意如果在类的构造函数中抛出异常,系统是不会调用它的析构函数的,处理方法是:如果在构造函数中要抛出异常,则在抛出前要记得删除申请的资源。

(2). 异常处理仅仅通过类型而不是通过值来匹配的,所以catch块的参数可以没有参数名称,只需要参数类型。

(3). 函数原型中的异常说明要与实现中的异常说明一致,否则容易引起异常冲突。

(4). 应该在throw语句后写上异常对象时,throw先通过Copy构造函数构造一个新对象,再把该新对象传递给 catch语句.
那么当异常抛出后新对象如何释放?异常处理机制保证:异常抛出的新对象并非创建在函数栈上,而是创建在专用的异常栈上,因此它才可以跨接多个函数而传递到上层否则在栈清空的过程中就会被销毁。所有从try到throw语句之间构造起来的对象的析构函数将被自动调用。但如果一直上溯到main函数后还没有找到匹配的catch块,那么系统调用terminate()终止整个程序,这种情况下不能保证所有局部对象会被正确地销毁。

(5). 派生类的异常扑获要放到父类异常扑获的前面,否则,派生类的异常无法被扑获。

(6).编写异常说明时,要确保派生类成员函数的异常说明和基类成员函数的异常说明一致,即派生类改写的虚函数的异常说明至少要和对应的基类虚函数的异常说明相同,甚至更加严格,更特殊。

注:与原文内容相比,有所调整

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值