C++异常处理 - 栈解旋,异常接口声明,异常类型和异常变量的生命周期
栈解旋(unwinding)
异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,都会被自动析构。析构的顺序与构造的顺序相反。这一过程称为栈的解旋(unwinding)。
demo 1
#include <iostream>
#include <cstdio>
using namespace std;
class MyException {};
class Test
{
public:
Test(int a = 0, int b = 0)
{
this->a = a;
this->b = b;
cout << "Test 构造函数执行" << "a:" << a << " b: " << b << endl;
}
void printT()
{
cout << "a:" << a << " b: " << b << endl;
}
~Test()
{
cout << "Test 析构函数执行" << "a:" << a << " b: " << b << endl;
}
private:
int a;
int b;
};
void myFunc() throw (MyException)
{
Test t1;
Test t2;
cout << "定义了两个栈变量,异常抛出后测试栈变量的如何被析构" << endl;
throw MyException();
}
int main()
{
//异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,
//都会被自动析构。析构的顺序与构造的顺序相反。
//这一过程称为栈的解旋(unwinding)
try
{
myFunc();
}
//catch(MyException &e) //这里不能访问异常对象
catch (MyException) //这里不能访问异常对象
{
cout << "接收到MyException类型异常" << endl;
}
catch (...)
{
cout << "未知类型异常" << endl;
}
return 0;
}
异常接口声明
1)为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型,例如:
void func() throw (A, B, C , D); //这个函数func()能够且只能抛出类型A B C D及其子类型的异常。
2)如果在函数声明中没有包含异常接口声明,则次函数可以抛掷任何类型的异常,例如:
void func();
3)一个不抛掷任何类型异常的函数可以声明为:
void func() throw();
4) 如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexpected函数会被调用,该函数默认行为调用terminate函数中止程序。
传统处理错误
#include <iostream>
#include <cstdio>
using namespace std;
// 传统的错误处理机制
int myStrcpy(char *to, char *from)
{
if (from == NULL) {
return 1;
}
if (to == NULL) {
return 2;
}
// copy时的场景检查
if (*from == 'a') {
return 3; // copy时错误
}
while (*from != '\0') {
*to = *from;
to++;
from++;
}
*to = '\0';
return 0;
}
int main()
{
int ret = 0;
char buf1[] = "zbcdefg";
char buf2[1024] = { 0 };
ret = myStrcpy(buf2, buf1);
if (ret != 0) {
switch (ret) {
case 1:
cout << "源buf出错!\n";
break;
case 2:
cout << "目的buf出错!\n";
break;
case 3:
cout << "copy过程出错!\n";
break;
default:
cout << "未知错误!\n";
break;
}
}
cout << "buf2:\n" << buf2;
cout << endl;
return 0;
}
throw char*
#include <iostream>
#include <cstdio>
using namespace std;
// throw char *
void myStrcpy(char *to, char *from)
{
if (from == NULL) {
throw "源buf出错";
}
if (to == NULL) {
throw "目的buf出错";
}
// copy时的场景检查
if (*from == 'a') {
throw "copy过程出错"; // copy时错误
}
while (*from != '\0') {
*to = *from;
to++;
from++;
}
*to = '\0';
return;
}
int main()
{
int ret = 0;
char buf1[] = "abcdefg";
char buf2[1024] = { 0 };
try
{
myStrcpy(buf2, buf1);
}
catch (int e) // e可以写可以不写
{
cout << e << "int类型异常" << endl;
}
catch (char *e)
{
cout << "char* 类型异常" << endl;
}
catch (...)
{
};
cout << endl;
return 0;
}
throw 类对象
#include <iostream>
#include <cstdio>
using namespace std;
class BadSrcType {};
class BadDestType {};
class BadProcessType
{
public:
BadProcessType()
{
cout << "BadProcessType构造函数do \n";
}
BadProcessType(const BadProcessType &obj)
{
cout << "BadProcessType copy构造函数do \n";
}
~BadProcessType()
{
cout << "BadProcessType析构函数do \n";
}
};
//throw 类对象 类型异常
void my_strcpy3(char *to, char *from)
{
if (from == NULL)
{
throw BadSrcType();
}
if (to == NULL)
{
throw BadDestType();
}
//copy是的 场景检查
if (*from == 'a')
{
printf("开始 BadProcessType类型异常 \n");
throw BadProcessType(); //会不会产生一个匿名对象?
}
if (*from == 'b')
{
throw &(BadProcessType()); //会不会产生一个匿名对象?
}
if (*from == 'c')
{
throw new BadProcessType; //会不会产生一个匿名对象?
}
while (*from != '\0')
{
*to = *from;
to++;
from++;
}
*to = '\0';
}
int main()
{
int ret = 0;
char buf1[] = "cbbcdefg";
char buf2[1024] = { 0 };
try
{
//my_strcpy1(buf2, buf1);
//my_strcpy2(buf2, buf1);
my_strcpy3(buf2, buf1);
}
catch (int e) //e可以写 也可以不写
{
cout << e << " int类型异常" << endl;
}
catch (char *e)
{
cout << e << " char* 类型异常" << endl;
}
//---
catch (BadSrcType e)
{
cout << " BadSrcType 类型异常" << endl;
}
catch (BadDestType e)
{
cout << " BadDestType 类型异常" << endl;
}
//结论1: 如果 接受异常的时候 使用一个异常变量,则copy构造异常变量.
/*
catch( BadProcessType e) //是把匿名对象copy给e 还是e还是那个匿名对象
{
cout << " BadProcessType 类型异常" << endl;
}
*/
/*结论2: 使用引用的话 会使用throw时候的那个对象
catch( BadProcessType &e) //是把匿名对象copy给e 还是e还是那个匿名对象
{
cout << " BadProcessType 类型异常" << endl;
}
*/
//结论3: 指针可以和引用/元素写在一块 但是引用和元素不能写在一块
catch (BadProcessType *e) //是把匿名对象copy给e 还是e还是那个匿名对象
{
cout << " BadProcessType 类型异常" << endl;
delete e;
}
//结论4: 类对象时, 使用引用比较合适
// --
catch (...)
{
cout << "未知 类型异常" << endl;
}
return 0;
}
C++异常处理 - 栈解旋,异常接口声明,异常类型和异常变量的生命周期的更多相关文章
- C++基础 (10) 第十天 C++中类型转换 异常 栈解旋 io操作
1之前内容的回顾 C语言中的类型转换(int)a 强转可读性太差了 C++把()拆分成了四种转换方式 static_cast static_cast在编译器编译阶段就进行转换了 2.dynamic_ ...
- 牛客网Java刷题知识点之什么是异常、异常处理的原理是什么、为什么要使用异常、异常体系、运行时异常、普通异常、自定义异常、异常链
不多说,直接上干货! 在这个世界不可能存在完美的东西,不管完美的思维有多么缜密,细心,我们都不可能考虑所有的因素,这就是所谓的智者千虑必有一失.同样的道理,计算机的世界也是不完美的,异常情况随时都会发 ...
- C++异常之三 异常处理接口声明
异常处理接口声明 1 一般为了方便程序员阅读代码,提高程序的可读性,会将函数中的异常类型声明至函数头后方,不用一行一行的找抛出内容: 2 这里要注意一点,这属于C++的标准语法,但在VS中这个操作不被 ...
- JAVA之旅(十)——异常的概述,Try-Catch,异常声明Throws,多异常处理,自定义异常,Throw和Throws的区别
JAVA之旅(十)--异常的概述,Try-Catch,异常声明Throws,多异常处理,自定义异常,Throw和Throws的区别 不知不觉,JAVA之旅这个系列已经更新到第十篇了,感觉如梦如幻,时间 ...
- java异常处理 throw RuntimeException时不需要同时方法中声明抛出throws 异常等待调用者catch进行捕获 子父类异常问题
package com.swift.exception1; public class Demo_Exception { public static void main(String[] args) { ...
- “全栈2019”Java异常第十五章:异常链详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- “全栈2019”Java异常第十三章:访问异常堆栈跟踪信息
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- “全栈2019”Java异常第一章:什么是异常?
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- C++异常之七 标准库里的异常类
标准库里的异常类 C++标准提供了一组标准异常类,这些类以基类 Exception 开始,标准程序库抛出的所有异常,都派生于该基类,这些类构成如图所示的异常类的派生继承关系,该基类提供一个成员函数 w ...
随机推荐
- Java第8次实验(IO流)
参考资料 本次作业参考文件 正则表达式参考资料 第1次实验 1. 字符流与文本文件:使用 PrintWriter(写),BufferedReader(读) 参考文件:基础代码目录Student.jav ...
- 为什么内部类访问的外部变量需要使用final修饰
因为生命周期的原因.方法中的局部变量,方法结束后这个变量就要释放掉,final保证这个变量始终指向一个对象.首先,内部类和外部类其实是处于同一个级别,内部类不会因为定义在方法中就会随着方法的执行完毕而 ...
- 20160220.CCPP体系详解(0030天)
程序片段(01):对称.c 内容概要:对称 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h ...
- J2EE中MVC的各层的设计原则及其编写注意事项
总结了下J2EE的MVC模式开发原则,很多细节处理好了是很有利于开发与维护的. 下面就从各层说起. 视图层 主要是客户端的显示,主要是JSP和HTML,随着Web的不断发展,许多基于Javascrip ...
- ROS(indigo) 用于机器人控制的图形化编程工具--code_it robot_blockly
0 简介: 编程语言有汇编,高级语言,解释语言等,现在图形化编程也越来越流行.图形化编程简单易学.8年前,微软推出了VPL用于机器人程序设计,如Python和JavaScript都可以用图形化框图实现 ...
- 关于在页面中针对不同版本的IE浏览器实现不同的JS或者CSS样式
一般会用到<!--[if IE]>这里是正常的html代码<![endif]--> 条件注释只能在windows Internet Explorer(以下简称IE)下使用,因此 ...
- 游戏引擎cocos2d-android使用大全
做手机游戏需要三个核心的类,即:SurfaceView,SurfaceHolder,Thread.帧数要在30帧左右是最好的. cocos2d游戏引擎 封装好的框架,可直接使用 cocos2d-and ...
- 使用Apache的ab进行压力测试
概述 ab是apache自带的压力测试工具,当安装完apache的时候,就可以在bin下面找到ab然后进行apache 负载压力测试. 后台测试开发中,常用的压力测试服务,php一般选择xampp,下 ...
- Gazebo機器人仿真學習探索筆記(五)環境模型
環境模型構建可以通過向其中添加模型實現,待之後補充,比較有趣的是建築物模型, 可以編輯多層樓層和房間,加入樓梯,窗戶和牆壁等,具體可以參考附錄,等有空再補充. 起伏地形環境構建可以參考之前內容:在Ga ...
- ROS探索总结(十六)——HRMRP机器人的设计
1. HRMRP简介 HRMRP(Hybrid Real-time Mobile Robot Platform,混合实时移动机器人平台)机器人是我在校期间和实验室的其他小伙伴一起从零开 ...