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++的异常处理机制不够完善,是否使用取决于具体的开发团队的要求。

相关推荐
Wang's Blog1 小时前
Java 项目实战: 交友项目 - 圈子功能的表设计方案
java·开发语言·交友
stolentime1 小时前
SOS DP学习笔记
c++·笔记·学习·算法·贪心算法·动态规划·二进制
轻舟技术A1 小时前
Rust 重写 Pi:会话启动耗时降 91%,就绪内存少 78%
开发语言·后端·rust
用户7624117567052 小时前
第四章 流程控制结构
c++
Jack N2 小时前
【Strapi 系列之五】前端怎么接?Next.js + Tailwind 拉取 Strapi 数据(含代码)
开发语言·前端·javascript·strapi
会编程的小孩2 小时前
Qt学习路线大纲图
c++
SuperHeroWu72 小时前
ArkGenie 的技术原理:从一段 SSE 到一个可交互 Surface
开发语言·php·交互
洁洁!3 小时前
手搓 C++ 线程池详细讲解以及如何面试应答
java·c++·面试