本文共 2285 字,大约阅读时间需要 7 分钟。
异常处理在C++中的详细指南
异常处理是一种允许两个独立开发的程序组件在程序执行时遇到不正常的情况相互通信的工具。它通过throw表达式引发异常,并通过try、catch语句块进行捕获和处理,使得程序能够更安全地应对潜在的错误和异常。
一、throw
1.概念
程序的异常检测部分使用throw表达式引发一个异常。它可以用于在程序中抛出错误或无法处理的问题。
2.格式
throw后跟的表达式可以是整型、浮点型、字符、字符串、类或函数等。执行throw时,后续的语句将不再执行,程序的执行权转移到对应的catch语句块中。
3.注意事项
- throw后面的语句不会执行。
- 如果throw指向的是基类指针,而指针实际指向的是派生类对象,则抛出的对象会被截断,只有基类部分会被抛出。
二、try-catch语句块
1.格式
try后面跟着一组语句,catch用于捕获异常。try和catch语句块的结构如下:
try { // 语句块} catch () { // 处理异常的语句}
2.注意事项
- try和catch都不能省去花括号,即使后面只有一条语句也不能省去。
- catch可以有多个,但try只能有一个。
- try和catch语句块可以嵌套。
- throw语句在try中抛出异常时,会跳转到与之匹配的catch语句块中。
三、catch的相关知识
1. catch的参数
- 如果catch的参数是引用类型,在catch语句块中可以修改参数值,进而修改对象本身。
- 如果catch的参数是基类类型,无法使用派生类特有的成员。
- catch的参数应放在继承链的最低端。
2. catch的书写顺序
- 如果多个catch语句之间存在继承关系,应按照继承链的顺序排列,最高端的类放在最后。
3. catch语句重新抛出
- catch语句可以重新抛出异常,传递给外层处理。语法格式为
throw;
。 - catch参数为引用类型时,修改后的值会被传递给外层catch语句。
四、构造函数的异常处理
构造函数的异常处理需要特殊注意:
- 初始化列表可能在构造函数执行之前抛出异常,因此构造函数的异常处理应放在初始化列表的后面。
- 使用函数try语句块(函数测试体),将try放在构造函数的初始化列表的冒号之前。
class A {public: A(int len) try : stuName(new char[len]) { if (len <= 0) throw length_error("长度过低"); } catch (length_error error) { cout << error.what(); }};
五、栈展开
异常处理过程中,程序会自动栈展开:
- 如果try中抛出异常后没有对应的catch语句块,异常会传递到调用函数。
- 最终,如果main函数也无法处理异常,程序会调用标准库函数terminate终止。
六、throw指定异常说明
1.概念
throw异常说明用于在函数的参数列表后指定函数可能抛出的异常类型。
2.格式
函数声明和定义都应写上throw异常说明。建议在函数指针声明和定义中也使用。
3.注意事项
- throw异常说明并不强制编译器检查函数是否抛出异常。
- throw后面可以跟着异常类型的说明。
七、noexcept异常说明
1.概念
noexcept用于声明函数不会抛出异常。它在C++11标准中引入,用来替代throw说明。
2.书写格式
- 在函数的参数列表后加上noexcept。
- 在类成员函数中,noexcept应放在const和引用限定符之后,虚函数=0之前。
八、异常说明与指针
1.规则
- 函数指针的异常说明与函数声明和定义一致。
- 如果函数指针声明了不会抛出异常,指针只能指向不会抛出异常的函数。
九、异常说明与拷贝控制
1.拷贝控制成员
- 合成拷贝控制成员的异常说明由编译器生成。
- 如果合成成员调用的函数可能抛出异常,则合成成员是noexcept(false)。
十、异常说明与虚函数
1.规则
- 如果虚函数承诺不会抛出异常,派生类对应的虚函数也必须做出相同承诺。
- 如果基类虚函数允许抛出异常,派生类对应的虚函数可以允许或不允许抛出异常。
十一、异常说明与析构函数
1.注意事项
- 析构函数中不能使用try语句块。
- 栈展开过程中,局部对象会自动销毁。
十二、异常处理的注意事项
1.栈展开过程中
- 局部对象在栈展开时会自动销毁。
- 析构函数中不可以放置try语句块。
2.不可抛出局部对象的指针
3.抛出基类指针
- throw表达式解引用基类指针时,会截断派生类部分,只抛出基类部分。
十三、标准异常
1.异常类
- C++标准库定义了多个异常类,用于报告运行时错误和逻辑错误。
- 常用异常类包括runtime_error、length_error、out_of_range等。
2.使用方式
- 使用using声明空间:
using namespace std;
- 各个异常类都有一个虚函数what(),返回错误信息。
3.自定义异常类
- 通过继承标准异常类,可以自定义自己的异常类型。
- 自定义异常类的初始化必须提供参数。
十四、异常处理的实际应用
1.输入验证
- 使用try-catch捕获用户输入错误。
- 抛出自定义异常类,提供友好的错误信息。
2.资源管理
- 使用智能指针管理动态内存。
- 在异常发生时自动释放内存。
通过以上内容,可以清晰地了解异常处理在C++中的应用和相关优化技巧。
转载地址:http://efur.baihongyu.com/