C++异常处理笔记

        异常处理(exception handling)允许将异常检测和解决的过程分离开来,程序中某一个模块出现了异常不会导致整个程序无法正确运行。C++语言提供了异常内部处理机制,该处理机制涉及三个关键字:try、catch和throw。它们的功能分别是:检测可能产生异常的语句块、捕获异常和引发异常。

使用try和catch()捕获异常

        要捕获语句可能发生的异常,可将它们放在try块中,并使用catch()块对try块可能引发的异常进行处理。

		try
		{
			int* numArray = new int[0xffffffff]
			delete[] numArray;
		}
		catch(std::bad_alloc& exp)   //捕获new引发(throw)的std::bad_alloc类对象
		{
			cout << "Exception encountered: " << exp.what() << endl;
			cout << "Go to end, sorry!" << endl;
		}
		catch(...)	//捕获未被其他catch块显式捕获的所有异常。
		{
			cout << "Exception encountered. Go to end, sorry! "
		}

使用trow引发异常

        上述捕获std::bad_alloc时实际是捕获new引发的std::bad_alloc类对象。也可以引发自己选择的异常。

double divide(int a, int b) {
    if(b == 0)
        /*
        1)当执行throw语句时,其后面的语句不会被执行。程序的控制权将转移到与之匹配
        的catch模块。
        2)throw可以抛出任意类型对象。通常情况下,抛出的异常为错误的编号、错误描述或用
        户自定义的异常类对象。例如上面的代码抛出的异常为一个C风格字符串常量(类型为const char*)。
        还可以抛出:
            throw -1;    //抛出一个整型数
            throw x;    //x为double类型对象
            throw MyException("Fatal Error");    //MyException为一个类类型
        */
        throw "Error, division by zero!";
    return a / b;
}

int func()
{
    try
    {
        cout << "Result is: " << divide(10, 0);
    }

    catch(const char* exp)  //捕获类型为char*的异常
    {
        cout << "Exception: " << exp << endl;
        cout << "sorry, can not continue!" << endl;
        /* 如果在某函数的catch块中处理了捕获的异常,还想通知本函数的调用者让其继续处理,就可以
        在catch块中指行“ throw; ”语句,这样的话就可以通知到本函数的调用者。*/
        throw;
    }
    
    return 0;

}

        每当使用throw引发异常时,编译器都将查找能处理该异常的catch(Type)。异常处理逻辑首先检查throw语句是否包含在try块中,如果是,则查找可处理这种异常的catch(Type)。如果throw语句不在try块内,或者没有与throw语句兼容的catch(),异常处理逻辑将继续在调用函数中寻找。因此,异常处理逻辑沿着调用栈向上逐个地在调用函数中寻找,直到找到可处理异常的catch(Type)。在退栈过程的每一步中,都将销毁当前函数的局部变量,这些局部变量的销毁顺序与创建顺序相反。

std::exception异常基类

       上述捕获std::alloc时实际捕获new引发的std::alloc对象。std::bad_alloc继承了C++标准类std::exception(在<exception>头文件中声明)。像bad::cast(试图使用dynamic_cast转换错误类型(没有继承关系的类型)时引发)、ios_base::failure(由iostream库中的函数和方法引发)都是从std::exception派生而来的。

        std::exception只定义了默认的构造函数、复制构造函数、复制运算符、虚析构函数和一个名为what的虚方法。可以继承exception类,并使用自定义版本的what成员。这个方法很有用,可以详细描述导致异常的原因。

        由于std::exception是众多异常类型的基类,因此可以使用catch(const exception&)捕获所有将std::exception作为基类的异常。

try
{
    ...
}
catch(const std::exception& exp)    //catch bas_alloc, bas_cast, etc
{
    cout << exp.what() << endl;
}

        从std::exception派生出自定义异常类(重点)

/*noexcept是C++11标准引入的新关键字,用来指明某个函数无法或不打算抛出异常。noexcept说明
必须放到形参列表后面,且函数的声明和定义处必须出现。如果是成员函数,则放置在const限定符之后,
在final、override或纯函数 =0之前*/
struct myExcetpion :public std::exception {
    virtual const char* what()const noexcept {return "Ooops!";}
};

/*下面代码将抛出/引发一个myException异常对象,该对象可被异常声明为基类excetpion类型的catch子
句捕获*/
try {
    throw myException();
}
catch(const exception &ex) {
    cerr << ex.what() << endl;
}

note:

        构造函数没有返回值,指出问题的唯一途径就是引发异常。

        异常处理最后退栈的时候,如果函数局部变量有类对象,那么也将调用其析构函数。如果因出现异常而被调用的析构函数也引发异常,将导致应用程序终止。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张帅峰_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值