深入理解c++中的异常处理机制

更新时间:2023-05-20 21:03:27 阅读: 评论:0

深⼊理解c++中的异常处理机制
异常处理
增强错误恢复能⼒是提⾼代码健壮性的最有⼒的途径之⼀,C语⾔中采⽤的错误处理⽅法被认为是紧耦合的,函数的使⽤者必须在⾮常靠近函数调⽤的地⽅编写错误处理代码,这样会使得其变得笨拙和难以使⽤。C++中引⼊了异常处理机制,这
是C++的主要特征之⼀,是考虑问题和处理错误的⼀种更好的⽅式。使⽤错误处理可以带来⼀些优点,如下:
· 错误处理代码的编写不再冗长乏味,并且不再和正常的代码混合在⼀起,只需要编写希望产⽣的代码,然后在后⾯某个单独的区段⾥编写处理错误的嗲吗。多次调⽤同⼀个函数,则只需要某个地⽅编写⼀次错误处理代码。
· 错误不能被忽略,如果⼀个函数必须向调⽤者发送⼀次错误信息。它将抛出⼀个描述这个错误的对象。
传统的错误处理和异常处理
在讨论异常处理之前,我们先谈谈C语⾔中的传统错误处理⽅法,这⾥列举了如下三种:
代办年审· 在函数中返回错误,函数会设置⼀个全局的错误状态标志。
· 使⽤信号来做信号处理系统,在函数中rai信号,通过signal来设置信号处理函数,这种⽅式耦合度⾮常⾼,⽽且不同的库产⽣的信号值可能会发⽣冲突
· 使⽤标准C库中的⾮局部跳转函数 tjmp和longjmp,这⾥使⽤tjmp和longjmp来演⽰下如何进⾏错误处理:
陶泥制作教程
<span >#include <iostream>
#include <tjmp.h>
jmp_buf static_buf; //⽤来存放处理器上下⽂,⽤于跳转
void do_jmp()
{ //do something,simetime occurs a little error
//调⽤longjmp后,会载⼊static_buf的处理器信息,然后第⼆个参数作为返回点的tjmp这个函数的返回值
longjmp(static_buf,10);//10是错误码,根据这个错误码来进⾏相应的处理
}
int main()
{
int ret = 0;
//将处理器信息保存到static_buf中,并返回0,相当于在这⾥做了⼀个标记,后⾯可以跳转过来
if((ret = tjmp(static_buf)) == 0) {
//要执⾏的代码
do_jmp();
} el {    //出现了错误
if (ret == 10)
std::cout << "a little error" << std::endl;
}
}</span>在线故事
错误处理⽅式看起来耦合度不是很⾼,正常代码和错误处理的代码分离了,处理处理的代码都汇聚在⼀起了。但是基于这种局部跳转的⽅式来处理代码,在 C++中却存在很严重的问题,那就是对象不能被析构,局部跳转后不会主动去调⽤已经实例化对象的析构函数。这将导致内存泄露的问题。下⾯这个例⼦充分显⽰了这点
#include <iostream>
#include <ctjmp>
using namespace std;
class ba {
public:
ba() {
cout << "ba construct func call" << endl;
}
~ba() {
cout << "~ba destruct func call" << endl;监控英语
}
};
jmp_buf static_buf;
void test_ba() {
ba b;
//do something
longjmp(static_buf,47);//进⾏了跳转,跳转后会发现b⽆法析构了
}
int main() {
if(tjmp(static_buf) == 0) {
cout << "deal with some thing" << endl;
test_ba();
} el {
cout << "catch a error" << endl;
}
}
在上⾯这段代码中,只有ba类的构造函数会被调⽤,当longjmp发⽣了跳转后,b这个实例将不会被
析构掉,但是执⾏流已经⽆法回到这⾥,b这个实例将不会被析构。这就是局部跳转⽤在C++中来处理错误的时候带来的⼀些问题,在C++中异常则不会有这些问题的存在。那么接下来看看如何定义⼀个异常,以及如何抛出⼀个异常和捕获异常吧.
异常的抛出
class MyError {
const char* const data;
public:
MyError(const char* const msg = 0):data(msg)会计实训报告
{
}
};
void do_error() {
throw MyError("something bad happend");
}
int main()
{
do_error();
保护牙齿的十个小常识
}
上⾯的例⼦中,通过throw抛出了⼀个异常类的实例,这个异常类,可以是任何⼀个⾃定义的类,通过实例化传⼊的参数可以表明发⽣的错误信息。其实异常就是⼀个带有异常信息的类⽽已。异常被抛出后,需要被捕获,从⽽可以从错误中进⾏恢复,那么接下来看看如何去捕获⼀个异常吧。在上⾯这个例⼦中使⽤抛出异常的⽅式来进⾏错误处理相⽐与之前使⽤局部跳转的实现来说,最⼤的不同之处就是异常抛出的代码块中,对象会被析构,称之为堆栈反解.
异常的捕获
C++中通过catch关键字来捕获异常,捕获异常后可以对异常进⾏处理,这个处理的语句块称为异常处理器。下⾯是⼀个简单的捕获异常的例⼦:
try{
//do something
throw string("this is exception");
} catch(const string& e) {
cout << "catch a exception " << e << endl;
}
catch有点像函数,可以有⼀个参数,throw抛出的异常对象,将会作为参数传递给匹配到到catch,然后进⼊异常处理器,上⾯的代码仅仅是展⽰了抛出⼀种异常的情况,加⼊try语句块中有可能会抛出多种异常的,那么该如何处理呢,这⾥是可以接多个catch语句块的,这将导致引⼊另外⼀个问题,那就是如何进⾏匹配。
异常的匹配
异常的匹配我认为是符合函数参数匹配的原则的,但是⼜有些不同,函数匹配的时候存在类型转换,但是异常则不然,在匹配过程中不会做类型的转换,下⾯的例⼦说明了这个事实:
#include <iostream>
using namespace std;
int main()
{
try{
}catch(int a) {
cout << "int" << endl;
}catch(char c) {
cout << "char" << endl;
}
}
上⾯的代码的输出结果是char,因为抛出的异常类型就是char,所以就匹配到了第⼆个异常处理器。可以发现在匹配过程中没有发⽣类型的转换。将 char转换为int。尽管异常处理器不做类型转换,但是基类可以匹配到派⽣类这个在函数和异常匹配中都是有效的,但是需要注意catch的形参需要是引⽤类型或者是指针类型,否则会导致切割派⽣类这个问题。
//基类
class Ba{
public:
Ba(string msg):m_msg(msg)
{
}
virtual void what(){
cout << m_msg << endl;
}
void test()
{
cout << "I am a CBa" << endl;
}
protected:
string m_msg;
};
//派⽣类,重新实现了虚函数
class CBa : public Ba
{
public:
CBa(string msg):Ba(msg)
{
}
void what()
{
cout << "CBa:" << m_msg << endl;
}
};
int main()
{
try {
//do some thing
//抛出派⽣类对象
throw CBa("I am a CBa exception");
}catch(Ba& e) {  //使⽤基类可以接收
e.what();
}
}
上⾯的这段代码可以正常的⼯作,实际上我们⽇常编写⾃⼰的异常处理函数的时候也是通过继承标准异常来实现字节的⾃定义异常的,但是如果将 Ba&换成Ba的话,将会导致对象被切割,例如下⾯这段代码将会编译出错,因为CBa被切割了,导致CBa中的test函数⽆法被调⽤。
普陀加点
try {
//do some thing
throw CBa("I am a CBa exception");
}catch(Ba e) {
}
到此为此,异常的匹配算是说清楚了,总结⼀下,异常匹配的时候基本上遵循下⾯⼏条规则:
异常匹配除了必须要是严格的类型匹配外,还⽀持下⾯⼏个类型转换.
· 允许⾮常量到常量的类型转换,也就是说可以抛出⼀个⾮常量类型,然后使⽤catch捕捉对应的常量类型版本
· 允许从派⽣类到基类的类型转换
· 允许数组被转换为数组指针,允许函数被转换为函数指针
怎样腌萝卜咸菜假想⼀种情况,当我要实现⼀代代码的时候,希望⽆论抛出什么类型的异常我都可以捕捉到,⽬前来说我们只能写上⼀⼤堆的catch语句捕获所有可能在代码中出现的异常来解决这个问题,很显然这样处理起来太过繁琐,幸好C++提供了⼀种可以捕捉任何异常的机制,可以使⽤下列代码中的语法。
catch(...) {
//异常处理器,这⾥可以捕捉任何异常,带来的问题就是⽆法或者异常信息
}

本文发布于:2023-05-20 21:03:27,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/711719.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:代码   函数   匹配   处理   对象   类型
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图