网站首页 > 技术文章 正文
- C++异常处理基本语法
- noexcept 修饰符和noexcept 运算符
- 异常修饰符与指针、虚函数
- C++标准异常类
本文重点讲C++异常机制的语法和使用,关于C++异常机制的实现原理,敬请期待。
- C++异常处理基本语法
通过 throw 和 try...catch 语句实现异常处理。throw 语句的语法如下:
throw 表达式;
意思是抛出异常,表达式代表一个异常,其值的类型可以是基本类型,也可以是类。
try...catch 语句的语法如下:
try {
语句组
}
catch(异常类型) {
异常处理代码
}
catch(异常类型) {
异常处理代码
}
catch 可以有多个,但至少要有一个。
try...catch 语句的执行过程是:
- 执行 try 块中的语句,如果执行的过程中没有异常拋出,那么执行完后就执行最后一个 catch 块后面的语句,即所有 catch 块中的语句都不会被执行;
- 如果 try 块执行的过程中拋出了异常,那么拋出异常后立即跳转到第一个“异常类型”和拋出的异常类型匹配的 catch 块中执行(称作异常被该 catch 块“捕获”),执行完后再跳转到最后一个 catch 块后面继续执行。
- 如果当前try…catch…块内找不到匹配该异常对象的catch语句,则由更外层的try…catch…块来处理该异常;层层递归回退,直到退到主函数main()都不能处理该异常,则调用terminate()终止程序
如果希望不论拋出哪种类型的异常都能捕获,可以编写如下 catch 块:
catch(...) {
...
}
2. noexcept修饰符 和 noexcept运算符
noexcept用来告诉编码者或编译器,函数是否会抛出异常。为什么要告诉编码者或编译器呢?首先,知道函数不会抛出异常让函数调用者不必再考虑如何处理异常;然后,如果编译器确认函数不会抛出异常,它就能执行某些特殊的优化操作。
关键字noexcept紧跟在函数的参数列表后面,例如:
void throwExcept() noexcept; //承诺函数不会抛出异常。
void throwExcept() ; //不确定函数是否会抛出异常。
我将其理解为异常承诺,即承诺不会抛出异常。我们也可以在函数指针的声明和定义中指定noexcept,在typedef或类型别名中则不能出现noexcept。
在成员函数中,noexcept修饰符需要跟在const及引用限定符之后,而在final、override或虚函数的=0之前。
违反异常承诺
大家需要清楚一个事实:编译器不会在编译时检查noexcept说明,如果一个函数在noexcept修饰的同时又含有throw或者调用了可能抛出异常的其它函数,编译器将顺利编译通过,并不会因为这种违反异常承诺的情况而报错。
void throwExcept() noexcept//承诺不会抛出异常
{
throw std::exception(); //抛出异常
}
一旦一个noexcept函数抛出了异常,程序就会调用std::terminate()以确保遵守程序在运行时不会抛出异常的承诺。
异常说明的实参
noexcept修饰符接受一个可选的实参,类型为bool:如果为true,则表示函数不会抛出异常;如果为false,则表示不确定函数是否会抛出异常。
void throwExcept() noexcept(false) ;
void throwExcept() noexcept(true) ; // noexcept(true) 相当于noexcept
void throwExcept() ; //隐式 noexcept(false)
noexcept运算符
noexcept运算符是一个一元运算符,返回值是bool,用于表示给定的表达式是否会抛出异常,如下面的例子:
void throwExcept() ;
void unknownThrow() noexcept(noexcept(throwExcept())) ;
//第一个noexcept是修饰符,第二个noexcept是运算符。
//noexcept(throwExcept())表示,如果throwExcept不抛出异常,则结果为true,否则为false。
//即unknownThrow()的异常说明与throwExcept()一致
noexcept作为运算符时,通常可以用于模板:
template<class T>
void fun() noexcept(noexcept(T());
//fun函数是否是一个noexcept函数,将由T()表达式是否为noexcept所决定。
3. 异常修饰符与指针、虚函数
如果我们为某个指针做了不抛出异常的声明,则该指针将只能指向不抛出异常的函数;返之,如果我们显示或隐式地说明了指针可能抛出异常,则该指针可以指向任何函数。
void throwExcept() noexcept;
void (*pf1)() noexcept = throwExcept; //正确,pf1和throwExcept承诺都不会抛出异常
void (*pf2)() = throwExcept; //正确,pf2可能抛出异常,throwExcept承诺不会抛出异常
void throwExcept();
void (*pf1)() noexcept = throwExcept; //错误,pf1承诺不抛出异常,throwExcept可能抛出异常
void (*pf2)() = throwExcept; //正确,pf2可能抛出异常,throwExcept可能抛出异常
如果基类的虚函数承诺了它不会抛出异常,则派生出来的函数也必须做出不会抛出异常的承诺;同样,如果基类的虚函数未做出承诺,则派生出来的函数即可以做出承诺也可以不做承诺。
4. C++标准异常类
bad_typeid、bad_cast、bad_alloc、ios_base::failure、out_of_range、logic_error、runtime_error 都是 exception 类的派生类,使用这些异常类需要包含头文件 <exception>。
std::exception | 最基本异常,所有异常都继承自它,只报告异常的发生。 |
std::bad_cast | 用 dynamic_cast 进行从多态基类对象(或引用)到派生类的引用的强制类型转换时,如果转换是不安全的,则会拋出此异常 |
std::ios_base::failure | 输入/输出库中的函数在失败时抛出的异常对象 |
std::bad_alloc | 在用 new 运算符进行动态内存分配时,如果没有足够的内存,则会引发此异常 |
std::bad_typeid | 使用 typeid 运算符时,如果其操作数是一个多态类的指针,而该指针的值为 NULL,则会拋出此异常 |
std::logic_error | 程序逻辑错误. |
std::out_of_range | 程序逻辑错误:用 vector 或 string 的 at 成员函数根据下标访问元素时,如果下标越界,则会拋出此异常 |
std::length_error | 程序逻辑错误:试图创建一个超出该类型最大长度的对象 |
std::demain_error | 程序逻辑错误:参数对应的结果值不存在 |
std::invalid_argument | 程序逻辑错误:无效参数 |
std::runtime_error | 运行时错误. |
std::rang_error | 运行时错误:产生了超出有意义值域范围的结果 |
std::overflow_error | 运行时错误:计算上溢 |
std::underflow_error | 运行时错误:计算下溢 |
- 上一篇: 大话C++语言:类继承与派生
- 下一篇: C++模板 - 21(静多态与泛型编程)
猜你喜欢
- 2025-01-20 C++|类型转换与运行时类型安全检查
- 2025-01-20 C++Qt开发——事件处理函数
- 2025-01-20 百度Linux C++后台开发面试题(个人整理)
- 2025-01-20 怎样才算学会了C++基础,一篇文章学习了解(包含Qt内容)
- 2025-01-20 C++通过aidl与Android系统服务通信(一)
- 2025-01-20 学习阅读C++编译器错误:函数声明中的荒谬错误
- 2025-01-20 朝文分享(54):深入C++(二十一)——多态
- 2025-01-20 c++多态
- 2025-01-20 深入探讨C++多线程性能优化
- 2025-01-20 【C++】C++ 11 新特性:使用示例
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)