C++~05异常处理

1. 概念

异常(exception)是程序的运行期间 出现的问题,因此程序的语法没有问题,但是逻辑出现了问题。

例如之前的容器越界问题:

程序一旦抛出了异常但是每一级都没有正确处理,就会造成程序运行的崩溃。

处理异常的方式有两种:

  • 向上级抛出异常
  • 直接捕获异常

2. 抛出异常

可以使用throw关键字在代码的任何位置抛出异常对象,这个异常对象理论上可以是任何类型,异常对象会在程序的调用层级中逐层传递,直到主函数。如果主函数中仍然不正确处理异常,则会运行终止。

复制代码
#include <iostream>`

`using namespace std;`

`double divide(double a,double b)`
`{`
`    // 定义抛出异常的规则`
`    if(b == 0)`
`        throw "除数为0!!!!!"; // const char*`
`    return a/b;`
`}`

`double add(double a,double b)`
`{`
`    return a+b;`
`}`

`/**`
` * @brief calculate 随便设计了一个计算规则`
` * @param a`
` * @param b`
` */`
`void calculate(double a,double b)`
`{`
`    double x = add(a,b);`
`    double y = divide(x,b);`
`    cout << y << endl;`
`}`


`int main()`
`{`
`    calculate(3,0);`

`    cout << "主函数结束" << endl;`
`    return 0;`
`}`
`

3. 捕获异常

捕获异常使用try和catch代码块配合使用,其中try代码块用于尝试执行一段有可能出现异常抛出的代码,这段代码越少越好。

try代码块在执行的过程中,可能出现以下几种情况:

2.1情况代码

复制代码
#include <iostream>`

`using namespace std;`

`double divide(double a,double b)`
`{`
`    // 定义抛出异常的规则`
`    if(b == 0)`
`        throw "除数为0!!!!!"; // const char*`
`    return a/b;`
`}`

`double add(double a,double b)`
`{`
`    return a+b;`
`}`

`/**`
` * @brief calculate 随便设计了一个计算规则`
` * @param a`
` * @param b`
` */`
`void calculate(double a,double b)`
`{`
`    double x = add(a,b);`
`    double y = divide(x,b);`
`    cout << y << endl;`
`}`


`int main()`
`{`
`    try`
`    {`
`        calculate(3,0);`
`        cout << "这句话不会得到执行" << endl;`
`    }catch(const char* e)`
`    {`
`        cout << "异常的弥补措施" << e << endl;`
`    }`

`    cout << "主函数结束" << endl;`

`    return 0;`
`}`
`

2.2 捕获失败

复制代码
#include <iostream>`

`using namespace std;`

`double divide(double a,double b)`
`{`
`    // 定义抛出异常的规则`
`    if(b == 0)`
`        throw "除数为0!!!!!"; // const char*`
`    return a/b;`
`}`

`double add(double a,double b)`
`{`
`    return a+b;`
`}`

`/**`
` * @brief calculate 随便设计了一个计算规则`
` * @param a`
` * @param b`
` */`
`void calculate(double a,double b)`
`{`
`    double x = add(a,b);`
`    double y = 0;`
`    try`
`    {`
`       y = divide(x,b); // 抛出const char*类型异常`
`       cout << "这句话不会执行" << endl;`
`    }catch(string s) // 捕获的却是string类型,不匹配,相当于没捕获,直接抛到上级`
`    {`
`       cout << "这里弥补措施也不会执行" << endl;`
`    }`
`    cout << y << endl;`
`}`


`int main()`
`{`

`    calculate(3,0);`

`    cout << "主函数结束" << endl;`

`    return 0;`
`}`
`

上面的代码还有一次捕获的机会,例如可以在calculate调用的位置再次捕获。

复制代码
#include <iostream>`

`using namespace std;`

`double divide(double a,double b)`
`{`
`    // 定义抛出异常的规则`
`    if(b == 0)`
`        throw "除数为0!!!!!"; // const char*`
`    return a/b;`
`}`

`double add(double a,double b)`
`{`
`    return a+b;`
`}`

`/**`
` * @brief calculate 随便设计了一个计算规则`
` * @param a`
` * @param b`
` */`
`void calculate(double a,double b)`
`{`
`    double x = add(a,b);`
`    double y = 0;`
`    try`
`    {`
`       y = divide(x,b); // 抛出const char*类型异常`
`       cout << "这句话不会执行" << endl;`
`    }catch(string s) // 捕获的却是string类型,不匹配,相当于没捕获,直接抛到上级`
`    {`
`       cout << "这里弥补措施也不会执行" << endl;`
`    }`
`    cout << y << endl;`
`}`


`int main()`
`{`
`    try`
`    {`
`        calculate(3,0);`
`    }catch(const char* e)`
`    {`
`        cout << "捕获成功!" << e << endl;`
`    }`

`    cout << "主函数结束" << endl;`

`    return 0;`
`}`
`

4. 标准异常族

C++已经预定义了一些异常的类型,使用前需要引入头文件#include <stdexcept>:

5. 自定义异常

实际开发中,往往会自定义一些异常类型,此时就需要通过继承加入标准异常族。

复制代码
#include <iostream>`
`#include <stdexcept> // 标准异常族`

`using namespace std;`

`/**`
` * @brief The ZeroException class`
` * 自定义异常类,继承了内置的异常基类`
` */`
`class ZeroException:public exception`
`{`
`public:`
`    // throw()表示异常规格说明,告诉编译器此函数安全,不会出现异常`
`    const char* what() const throw()`
`    {`
`        return "除数为0!!!!!";`
`    }`
`};`

`double divide(double a,double b)`
`{`
`    if(b == 0)`
`        throw ZeroException(); // 抛出自定义异常`
`    return a/b;`
`}`


`int main()`
`{`
`    try`
`    {`
`        divide(3,0);`
`    }catch(const ZeroException& e)`
`    {`
`        cout << "做出一些弥补的措施" << endl;`
`        cout << e.what() << endl; // 打印错误信息`
`    }`

`    cout << "主函数结束" << endl;`

`    return 0;`
`}`
`

6. 捕获基类异常

如果不能捕获正确的异常类型,此时也可以使用基类异常类型进行捕获。

复制代码
#include <iostream>`
`#include <stdexcept> // 标准异常族`

`using namespace std;`

`void func(int i)`
`{`
`    if(i % 2 == 0)`
`        throw length_error("A");`
`    else`
`        throw domain_error("B");`
`}`

`int main()`
`{`
`    try`
`    {`
`        func(2);`
`    }catch(const logic_error& e)`
`    {`
`        cout << "捕获异常" << e.what() << endl;`
`    }`

`    cout << "主函数结束" << endl;`

`    return 0;`
`}`
`

7. 多重捕获

try-catch代码块中,catch块可以有多个,当进行异常捕获时,逐个进行对比捕获,通常会把派生类类异常放在前面,基类异常放在后面。

复制代码
#include <iostream>`
`#include <stdexcept> // 标准异常族`

`using namespace std;`

`void func(int i)`
`{`
`    if(i % 2 == 0)`
`        throw length_error("A");`
`    else`
`        throw range_error("B");`
`}`

`int main()`
`{`
`    try`
`    {`
`        func(1);`
`    }catch(const length_error& e)`
`    {`
`        cout << "捕获异常A" << e.what() << endl;`
`    }catch(const logic_error& e)`
`    {`
`        cout << "捕获异常B" << e.what() << endl;`
`    }catch(const exception& e)`
`    {`
`        cout << "捕获异常C" << e.what() << endl;`
`    }`

`    cout << "主函数结束" << endl;`

`    return 0;`
`}`
`

C++的异常处理机制不够完善,是否使用取决于具体的开发团队的要求。

相关推荐
爱笑的k117 小时前
nano-vllm 源码剖析:千行 Python 手写离线推理引擎的调度、显存与并行时序
开发语言·python·vllm
X1A0RAN8 小时前
PPT 图片批量处理教程:导出全部幻灯片 · 提取全部素材
开发语言·javascript·powerpoint
熊猫钓鱼>_>9 小时前
普通用户视角的端侧智能体验手记【鸿蒙心迹】
开发语言·人工智能·华为·智能手机·性能优化·ai编程·harmonyos
瑞雪兆丰年兮9 小时前
JavaWeb-day13-SpringBootWeb事务管理&AOP
java·开发语言·springboot·javaweb·事务·web·aop
布莱克60511 小时前
Swift 常量详解:从 let 到编译期优化
服务器·开发语言·ssh·swift·常量·let
布莱克60511 小时前
Swift 可选类型(Optionals)详解:从原理到实战
开发语言·安全·ssh·swift·optional·可选类型
老歌老听老掉牙11 小时前
案例 7:二维 Rosenbrock 函数最小值(香蕉函数)
c++·pso
Severus_black12 小时前
【C++初阶】Stack、Queue算法题大练兵!
c语言·c++·算法·stl
瑞雪兆丰年兮13 小时前
JavaWeb-day14-SpringBootWeb原理篇
java·开发语言·spring boot·spring·bean·mybatis·javaweb
SomeOtherTime15 小时前
Rust生命周期介绍(AI回答)
开发语言·后端·rust