当程序遇到一个异常或一个严重的错误时,通常意味着它不能继续正常运行并且需要停止执行。任何的设计都离不开对异常与错误的处理。如果设计者不主动规避程序异常,往往在程序发生异常时,会被系统终止而直接退出。这对使用者来说,是很不友好的。

如果主动处理异常,可以显式地提示错误地发生,也可以避免程序异常终止。更好的处理是,在设计时,预估一些错误,让用户避开这些错误以让程序顺利运行。对一些无法预知的异常,也需要我们通过VC++的异常处理机制,显式地告诉错误已发生,并保证程序的继续进行。

VC++提供了两种不同性质的异常处理:
    结构化异常SEH (Structured Exception Handling, ) 和 类型化的 C++异常。
    SEH 是VC++编译器特有的,因此如果你想要编写可移植的代码,就不应当使用SEH。他只能在 Windows系统中产生作用。如果只想编写 Windows 应用。那么,最好选择SEH来处理异常。SEH 比 类型化的C++异常 更方便,更灵活。

结构化异常SEH

__try,__except,__finally   是Windows系列操作系统平台上提供的SEH的处理模型。

__try,__except:表示 try {}语句中发生异常,将转到 except () {}模块执行。如果try{}没有异常。except模块被跳过。继续执行 except {} 之后的代码。

__try, __finally :  表示try {}语句无论有没异常发生,finally{}模块都会被执行。__try __finally 没有太多用法,不作详细说明。只要用对地方就行了。

    ___leave : 一般用在 try{} 里。表示退出 try 模块,并不执行 leave之后的语句。根当于函数中的return. 不过,这里只退出try{}.

__try,__except 简单用法示范

int _tmain(int argc, _TCHAR* argv[])
{int v1, v2;v1 = 1; v2 = 0;double x=0;__try{// if (v2==0) ___leave; // 加上___leave这一句。leave 之后的代码都不会执行 跳出 try 执行 try except 之后的代码。x = v1 / v2; // x = myFunc(v1, v2);cout << x << endl;}__except (1) // 试着改为 0 或 -1 看看效果
    {cout << "Error!" << endl;}system("pause");return 0;
}

__except 后的括号里,是一个表达式或一个数值。表达式返回的也应是一个数值。这个数值 为 1-3 表明 except的三种处理方试:

  • __except(-1)  异常终止,退出程序。很少用这个。除非人为想终止自己的程序。

  • __except(0) 跳出当前异常,继续由下一个异常 except 来处理。

  • __except(1) 接受异常。执行异常 {} 中的语句。以上二个值 -1, 0 都不会执行 except{ ... } 中的语句。

这三个值,在 Windows 中,有三个常量代表:

EXCEPTION_CONTINUE_EXECUTION (– 1)
        EXCEPTION_CONTINUE_SEARCH (0)
        EXCEPTION_EXECUTE_HANDLER (1)

我们也可以通过一个函数来返回三个值。让 except 被触发时,作更精准的处理。而这个函数一般会调用 Windows的 两个错误代码处理的API函数:
        GetExceptionCode() : 返回错误代码;
        GetExceptionInformation() : 取得错误信息结构。

嵌入异常处理与自定义处理函数示例:

int ErrorFunc(unsigned int code, struct _EXCEPTION_POINTERS *ep)
{puts("my Error infomathion.");if (code == EXCEPTION_ACCESS_VIOLATION) {puts("caught AV as expected.");return EXCEPTION_EXECUTE_HANDLER; // =1 执行被调用的 except 处理过程
}else {puts("didn't catch AV, unexpected.");return EXCEPTION_CONTINUE_SEARCH; // =0 继续让下一个 except处理
};
}double myFunc(int a, int b)
{double r;//exit(0);
    __try{ r = a / b;cout << "Cacle..." << endl;} __except (ErrorFunc(GetExceptionCode(), GetExceptionInformation())){// 如果 ErrorFunc 返回值为 1 下面的语句才会执行unsigned int code = GetExceptionCode();cout << "ERROR!:" << code  << endl;//throw;
    }cout << "...end1..." << endl;return r;
}int _tmain(int argc, _TCHAR* argv[])
{int v1, v2;v1 = 1; v2 = 0;double x=0;__try{x = myFunc(v1, v2); // 调用函数,嵌入式 __try __except 示范。  cout << x << endl;}__except (1){cout << "Error!" << endl;}cout << "...end2..." << endl;system("pause");return 0;
}

SEH异常处理模型中,异常通过RaiseException()函数抛出。RaiseException()函数的作用类似于C++异常模型中的throw。可以通过这个函数,主动处理预知的异常。

主动抛出异常示例:

int _tmain(int argc, _TCHAR* argv[])
{int v1, v2;v1 = 1; v2 = 0;double x=0;__try{// x = v1 / v2;RaiseException(100, 0, 0, NULL); //主动抛出错误 100 是自己定义的异常代码cout << x << endl;}__except (1){UINT code = GetExceptionCode();if (code==100) // 判断自己抛出的异常代码cout << "Error! Code:"<< code << endl;}cout << "...end..." << endl;system("pause");return 0;
}

类型化的 C++异常

C++的异常处理很简单,就是三个关键字 try, throw, catch来完成。他在很多地方有关系性作用。但这里只作简单地了解。

try
{//这里写入一些代码int a=10, b=0;int x;if (b==0) throw 1; // 抛出异常。终止以下的代码执行 。if (a==1);throw 2; // 再抛出个异常。终止以下的代码执行 。
  x = a/b; // b=0. 会产生运算异常。
}
catch int i
{if (i==1) // 由 throw 抛出的值 =1cout << "b=0 is error!" <<endl;if (i==2) // 由 throw 抛出的值 =2cout << "i=1 is error!" <<endl;
}
catch(...){} //接受所有异常

如 果想用 try{} catch{}来捕捉一些意想不到的异常,是靠不住的。也就是说他需要在 try {} 中主动发现异常,然后通过 throw, 抛出异常,让 catch来处理。如果是你发现不了的异常,如果无法throw出来,也就无法处理。如上例中: if (b==0) throw 1; 这句不要。执行到 x=a/b; 是会产生一个系统错误。try{}catch{} 中不会主动识别这个异常。但 try , catch 的用法有很多。可以找更多的资料去了解下。我也未了解清楚。

以下内容容易不被了解:

catch 没有捕获到匹配的异常的时候,会调用默认的终止函数。可以调用 set_terminate()来设置终止函数,参数是一个函数指针,类型是:void (*terminate)(); 实际上是调用默认的unexpected()函数,而这个默认的unexpected() 调用了 set_terminate() 中设定的终止函数。可以用set_unexpected()来设置unexpected。

如下:( 但这一段代码在VC下编译执行不会发生什么!)

void myUnexpected() {cerr << "unexpected called\n";throw 0;     // throws int (in exception-specification)
}void myfunction() throw (int) {throw 'x';   // throws char (not in exception-specification)
}
int _tmain(int argc, _TCHAR* argv[])
{int v1, v2;v1 = 1; v2 = 0;double x=0;set_unexpected(myUnexpected);try{myfunction();  // x = v1 / v2;
    }catch (int) {cerr << "caught int/n";}catch (...){ cerr << "caught other exception (non-compliant compiler?)\n"; };
}

VC 在Release方式下如果选择了编译器代码优化选项,则会去搜索try块中的代码, 如果没有找到throw代码, 就会认为try catch结构是多余的, 给优化掉。 这样造成在Release模式下。如果不在 try{}中主动throw抛出一个异常。在VC 的 Release编译模式下,try  catch 是被忽略掉的。

转载于:https://www.cnblogs.com/iSixth/p/4179350.html

备忘:VC++ 中的异常处理相关推荐

  1. 备忘: VC++ 自动适用编译两种模式库文件 (DLL, LIB)

    为什么80%的码农都做不了架构师?>>>    一个好的程序设计规划总会有属于自己的基础代码库.重用这些代码库,DLL或LIB方式最好的选择之一.在写新的项目或程序是,我们不可能每次 ...

  2. 纪录备忘:应用中的脚本应用

    --1.服务器端的下拉框 <asp:DropDownList ID="ddlSelectLineType" runat="server" Width=&q ...

  3. [备忘]silverlight中关于“复制到输出目录”和“生成操作”

    复制到输出目录 中的 输出目录 值xap 所在目录,一般指承载sl项目的codebin目录 生成操作 可以确定 文件 是到 程序集中 还是 xap包中 还是在目录中 适合sl中视频或音频资源的选项有四 ...

  4. java调用visa的dll库,查看新闻/公告--[备忘]Java中,使用JNA调用Visa32.dll,控制频谱仪~~...

    Java中,使用JNA调用Visa32.dll,控制频谱仪~~ C:\Program Files\Agilent\IO Libraries Suite\ 有visa.chm,是方法和属性的说明. 首先 ...

  5. fib函数用python编写_Python中利用函数装饰器实现备忘功能

    "备忘"的定义 "memoization"(备忘)这个词是由Donald Michie在1968年提出的,它基于拉丁语单词"memorandum&qu ...

  6. VB.net小技巧——VB中利用TreeView控件和Box控件做知识备忘

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 VB.net小技巧--VB中利用TreeView控件和Box控件做知识备忘 这里不涉及代码的展示,主要是为了阐述一种做笔记的思想. 为 ...

  7. 深度学习模型中的参数数量(备忘)

    原文地址:huay' blog/模型中的参数数量(备忘) 记录模型参数数量的计算方法 最早使用 tensorflow 的时候没怎么注意这个问题: 后面高级 API 用的多了,有点忘记怎么计算模型的参数 ...

  8. Java中Steam流的用法及使用备忘

    文章目录 Java中Steam流的用法及使用备忘 一. 流的常用创建方法 1-1 使用Collection下的 stream() 和 parallelStream() 方法 1-2 使用Arrays ...

  9. Java中操作Xml使用备忘

    List item 文章目录 Java中操作Xml使用备忘 1. Hutool中XmlUtil的使用简介 2. Hutool中XmlUtil快速读取Xml字符串某个节点值 [简单取值时,推荐使用] 2 ...

最新文章

  1. 皮一皮:这是歪打正着了???
  2. 利用TaskCompletionSource将EAP转换成TAP
  3. 详解linux的initrd
  4. oracle输出xml文件格式,在oracle中通过字段信息生成xml文件
  5. html 手写字效果,canvas画布实现手写签名效果的示例代码
  6. 深圳linux测试题库,Linux认证考试题库及答案
  7. 初学者python笔记(面向对象编程、类与对象)
  8. warning C4819 解决方案 warning C4819: The file contains a character that cannot be represented in the cu
  9. mysql数据库的操作dao vo_nutzdao+druid使用非数据库实体VO接收返回的对象一直报“Table ‘xxxxx’ doesn't exist”...
  10. 28线性空间02——坐标、坐标变换与基变换、过度矩阵
  11. Mybatis中的DataSource配置
  12. 2022年最新《谷粒学院开发教程》:7 - 渲染前台页面
  13. 混合式教学模式在课堂中的应用
  14. linux系统 锐捷_Ubuntu Linux锐捷安装方法
  15. 工具开发——端口开放扫描
  16. Navicat安装教程(超详细)
  17. python-numpy常用知识汇总
  18. 用计算机算术表白,数学表白密码
  19. CSR蓝牙芯片进测试模式方法
  20. 协议栈之packet_type

热门文章

  1. 允许Sublime编辑器在Ubuntu上输入中文
  2. views视图函数-模板语法
  3. 360智能工程中心期待你的加入
  4. 算法题存档20190304
  5. asp.net的一些对话
  6. CentOS+Nginx一步一步开始配置负载均衡
  7. 【实战】docker-compose 编排 多个docker 组成一个集群并做负载
  8. BASE64Encoder及BASE64Decoder的正确用法
  9. QEMU多进程(Multi-process QEMU)及vfio-user应用
  10. qemu-img创建qcow2虚拟磁盘的预分配策略