概念
C++ 异常(Exception)是语言内置的运行时错误处理机制,用于在程序执行出现非正常状态时,将错误信息从错误发生点沿着函数调用链向上传递到专门的错误处理位置 ,实现错误检测 与错误处理 的解耦
其核心设计思想是:底层逻辑专注于功能实现,遇到错误只需抛出异常;上层业务逻辑专注于错误处理,根据异常类型做出响应,无需在每一层调用都做错误码判断和透传

异常的机理
程序出现问题时,我们通过抛出(throw)一个对象来引发一个异常,该对象的类型以及当前的调用
链会随着上述代码的过程依次寻找匹配的catch
调用链中与该对象类型匹配且离抛出异常位置最近的那一个catch才能捕获到异常。根据抛出对象的类型和内容,程序的抛出异常部分告知异常处理部分到底发生了什么错误
当throw执行时,throw后面的语句将不再被执行,程序的执行从throw位置跳到与之匹配的catch模块
这里还有两个重要的含义:1、沿着调用链的函数可能提早退出。2、一旦程序开始执行异常处理程序,沿着调用链创建的对象都将销毁。
因此抛出异常对象后,编译器会自己生成一个异常对象的拷贝,这个拷贝的对象会在catch子句后销毁。(这里的处理类似于函数的传值返回------返回的是一个拷贝值)
如果到main函数后还没有找到匹配的catch,机器就会调用标准库的teminate函数终止程序
一般情况下抛出的对象是要和catch中的类型完全一致,但也可有类型的转换,如非常量向常量(const)的转换、允许数组向数组指针转换、允许函数向函数指针转换以及子类向父类的转换等。其中子类向父类的转换是十分有用且常见的,继承体系基本都是通过这种方式设计的
如果到main函数,异常仍旧没有被匹配就会终止程序,不是发生严重错误的情况下,我们是不期望程序终止的(如果程序终止,相当于我们平常用的软件崩溃了,一般不会允许出现这种情况,都是将异常信息加载到日志,然后等发现时修复),所以一般main函数中最后都会使用catch(...),它可以捕获任意类型的异常,但是是不知道异常错误是什么
hrow; (不带任何参数)只能写在catch内**,**作用是重新抛出当前正在捕获的原始异常对象 ,不会拷贝,直接继续向上传递原来那个异常.

异常机制带来的问题及解决措施
异常如果处理不当,会出现内存泄漏问题。如下代码,我们不写catch(...)以及内部的delete(防止出现异常,不执行函数结尾的delete)以及函数结尾写delete(如果不写,没有异常时就会有内存泄漏),就会出现内存泄漏问题
其次析构函数中对待异常要谨慎处理,如果要释放10个资源,释放了六个时出现异常剩下的四个可能没有释放,因此也需要类似下述代码的捕获处理
但是这样会代码十分不美观、冗余,C++11增加了智能指针来处理异常出现时的资源释放问题,我们下一篇文章介绍它

因此对于用户和编译器而言,如果能预先知道某个程序会不会抛出异常就太棒了,知道某个函数是否会抛出异常有助于简化调用函数的代码。C++98就想到了这一点,但当时的处理语法有点冗余,C++11提出了新的语法------在函数参数列表后加一个关键字noexcept,表示不会有异常,但是没加的话就可能会有异常
当函数用noexcpt修饰时内部还写了throw,编译器不会报错(但有的可能会报警告),但是运行时如果真出现异常了,就会调用terminate函数终止程序
此外noexcept关键字还可以检查一个表达式是否会抛出异常,可能会抛出就为false,不会抛出就为true
C++标准库定义了一套异常继承体系库,我们编写代码时可以在主函数写catch,用exception(这个库异常类的基类)捕获,要想获取异常信息就调用what函数(what是⼀个虚函数)
下面是这个异常继承体系库的链接,大家可以让大模型讲解一下