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 ...
随机推荐
- PHP 5 MySQLi 函数
在 PHP 中使用 MySQLi 函数需要注意的是:你需要添加对 MySQLi 扩展的支持. PHP MySQLi 简介 PHP MySQLi = PHP MySQL Improved! MySQLi ...
- SQL Server 扩展事件(Extented Events)从入门到进阶(2)——在GUI中创建基础扩展事件
本文属于 SQL Server 扩展事件(Extented Events)从入门到进阶 系列 第一篇文章中提到了如何在Profiler中创建跟踪(trace),并以服务器端(server-side)跟 ...
- Redis中的关系查询
本文对Redis如何保存关系型数据,以及如何对其匹配.范围.模糊查询进行举例讲解,其中模糊查询功能基于最新的2.8.9以后版本. 1 关系型数据的存储 以Staff对象为例,在关系型数据库或类似Gri ...
- 十六进制字符串转化为十进制值strtoul函数
eg: NSString *strtest =@"7fffffff"; NSUInteger val = strtoul([[strtest substringWithRange: ...
- iOS界面不能点击(tableView 的cell 不能使用点击事件,tableView也不能上下滚动)
iOS开发中间遇到了很多问题,有些后来又遇到,竟然忘记怎么处理了,所以还是来写下博客记录自己遇到的问题,方便自己也方便别人. 之前想的是项目小,就用storyboard在绘制界面,但是项目慢慢的扩展, ...
- Android Multimedia框架总结(十)Stagefright框架之音视频输出过程
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52560012 前言:上篇文中最后 ...
- 21 FragmentTabHost +Fragment代码案例
注意头导航标签过多会被压缩并 结构 MainActivity.java package com.qf.day21_fragmenttabhost_demo1; import com.qf.day21_ ...
- 简单搭建iOS开发项目框架
今天我们来谈谈如何搭建框架,框架需要做一些什么. 第一步:找到我们的目标我们的目标是让其他开发人员拿到手后即可写页面,不再需要考虑其他的问题. 第二步:我们需要做哪些东西各位跟着我一步一步来进行. 假 ...
- 深入理解CoordinatorLayout.Behavior
要研究的几个问题 一.Behavior是什么?为什么要用Behavior? 二.怎么使用Behavior? 三.从源码角度看为什么要这么使用Behavior? 一.Behavior是什么?为什么要用B ...
- Android存储之SharedPreferences
Android数据存储之SharedPreferences SharedPreferences对象初始化 SharedPreferences mSharedPreferences = getShare ...