怎么在网上做装修网站,网站顶部有空白,做网站的博客,淮安建立公司网站流程转自#xff1a;【C学习笔记】C异常处理#xff01;你绝对不能错过的干货#xff01; - 知乎 合理地使用C异常处理#xff0c;能够使我们写出来的程序更加稳定强健#xff0c;不易崩溃。那么#xff0c;应该如何使用C异常处理呢#xff1f;下面#xff0c;我们就来向大…转自【C学习笔记】C异常处理你绝对不能错过的干货 - 知乎 合理地使用C异常处理能够使我们写出来的程序更加稳定强健不易崩溃。那么应该如何使用C异常处理呢下面我们就来向大家介绍最简单也是最常用的异常处理语句 。
一、什么是异常
用官方的话来说就是程序在执行过程中产生的问题换句通俗的话来讲就是程序执行的出现的异常比如程序崩了、内存泄漏了、数组越界以及其他异常信息的出现。
异常提供了一种转移程序控制权的方式。C 异常处理涉及到三个关键字try、catch、throw。
throw: 当问题出现时程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
catch: 在您想要处理问题的地方通过异常处理程序捕获异常。catch 关键字用于捕获异常。
try: try 块中存放可能出现异常的代码。它后面通常跟着一个或多个 catch 块。
如果有一个块抛出一个异常捕获异常的方法会使用 try 和 catch 关键字。try 块中放置可能抛出异常的代码try 块中的代码被称为保护代码。使用 try/catch 语句的语法如下所示
try { // 保护代码 }catch( ExceptionName e1 ) { // catch 块 }catch( ExceptionName e2 ) { // catch 块 }catch( ExceptionName eN ) { // catch 块 }如果 try 块在不同的情境下会抛出不同的异常这个时候可以尝试罗列多个 catch 语句用于捕获不同类型的异常。
二、抛出异常
您可以使用 throw 语句在代码块中的任何地方抛出异常。throw 语句的操作数可以是任意的表达式表达式的结果的类型决定了抛出的异常的类型。
以下是尝试除以零时抛出异常的实例
double division(int a, int b) { if( b 0 ) { throw Division by zero condition!; } return (a/b); }三、捕获异常
catch 块跟在 try 块后面用于捕获异常。您可以指定想要捕捉的异常类型这是由 catch 关键字后的括号内的异常声明决定的。
try { // 保护代码 }catch( ExceptionName e ) { // 处理 ExceptionName 异常的代码 }上面的代码会捕获一个类型为 ExceptionName 的异常。如果您想让 catch 块能够处理 try 块抛出的任何类型的异常则必须在异常声明的括号内使用省略号 ...如下所示
try { // 保护代码 }catch(...) { // 能处理任何异常的代码 }下面是一个实例抛出一个除以零的异常并在 catch 块中捕获该异常。
#include iostream using namespace std; double division(int a, int b) { if( b 0 ) { throw Division by zero condition!; } return (a/b); } int main () { int x 50; int y 0; double z 0; try { z division(x, y); cout z endl; }catch (const char* msg) { cerr msg endl; } return 0; }由于我们抛出了一个类型为 const char* 的异常因此当捕获该异常时我们必须在 catch 块中使用 const char*。当上面的代码被编译和执行时它会产生下列结果
Division by zero condition!四、异常的处理规则
throw抛出的异常类型与catch抓取的异常类型要一致
throw抛出的异常类型可以是子类对象catch可以是父类对象
catch块的参数推荐采用地址传递而不是值传递不仅可以提高效率还可以利用对象的多态性。另外派生类的异常捕获要放到父类异常扑获的前面否则派生类的异常无法被扑获
如果使用catch参数中
使用基类捕获派生类对象一定要使用传递引用的方式
例如catch (exception e)
异常是通过抛出对象而引发的该对象的类型决定了应该激活哪个处理代码
被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那一个
在try的语句块内声明的变量在外部是不可以访问的即使是在catch子句内也不可以访问
栈展开会沿着嵌套函数的调用链不断查找直到找到了已抛出的异常匹配的catch子句。如果抛出的异常一直没有函数捕获(catch)则会一直上传到c运行系统那里导致整个程序的终止。
五、C 标准的异常
C 提供了一系列标准的异常定义在 exception 中我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的如下所示 下表是对上面层次结构中出现的每个异常的说明
异常描述 六、定义新的异常
您可以通过继承和重载 exception 类来定义新的异常。下面的实例演示了如何使用 std::exception 类来实现自己的异常
实例
#include iostream #include exception using namespace std; struct MyException : public exception { const char * what () const throw () { return C Exception; } }; int main() { try { throw MyException(); } catch(MyException e) { std::cout MyException caught std::endl; std::cout e.what() std::endl; } catch(std::exception e) { //其他的错误 } }这将产生以下结果
MyException caught C Exception在这里what() 是异常类提供的一个公共方法它已被所有子异常类重载。这将返回异常产生的原因。
七、总结
1. 使用异常处理的优点
传统错误处理技术检查到一个错误只会返回退出码或者终止程序等等我们只知道有错误但不能更清楚知道是哪种错误。使用异常把错误和处理分开来由库函数抛出异常由调用者捕获这个异常调用者就可以知道程序函数库调用出现的错误是什么错误并去处理而是否终止程序就把握在调用者手里了。
2. 使用异常的缺点
如果使用异常光凭查看代码是很难评估程序的控制流函数返回点可能在你意料之外这就导致了代码管理和调试的困难。启动异常使得生成的二进制文件体积变大延长了编译时间还可能会增加地址空间的压力。
C没有垃圾回收机制资源需要自己管理。有了异常非常容易导致内存泄漏、死锁等异常安全问题。 这个需要使用RAII来处理资源的管理问题。学习成本较高。
C标准库的异常体系定义得不好导致大家各自定义各自的异常体系非常的混乱。
3. 什么时候使用异常
建议除非已有的项目或底层库中使用了异常要不然尽量不要使用异常虽然提供了方便但是开销也大。
4. 程序所有的异常都可以catch到吗
并非如此只有发生异常并且又抛出异常的情况才能被 catch 到。例如数组下标访问越界的情况系统是不会自身抛出异常的所以我们无论怎么 catch 都是无效的在这种情况我们需要自定义抛出类型判断数组下标是否越界然后再根据自身需要throw自定义异常对象这样才可以catch到异常并进行进一步处理。 看到这里你是不是对“C”又有了一点新的认知呢~
如果你喜欢这篇文章的话动动小指加个关注哦~
如果你也想成为程序员想要快速掌握编程这里为你分享一个学习企鹅圈子
里面有资深专业软件开发工程师在线解答你的所有疑惑~C语言入门“so easy”
资料包含编程入门、游戏编程、课程设计、黑客等。