栈解旋(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++异常处理 - 栈解旋,异常接口声明,异常类型和异常变量的生命周期的更多相关文章

  1. C++基础 (10) 第十天 C++中类型转换 异常 栈解旋 io操作

    1之前内容的回顾 C语言中的类型转换(int)a  强转可读性太差了 C++把()拆分成了四种转换方式 static_cast static_cast在编译器编译阶段就进行转换了 2.dynamic_ ...

  2. 牛客网Java刷题知识点之什么是异常、异常处理的原理是什么、为什么要使用异常、异常体系、运行时异常、普通异常、自定义异常、异常链

    不多说,直接上干货! 在这个世界不可能存在完美的东西,不管完美的思维有多么缜密,细心,我们都不可能考虑所有的因素,这就是所谓的智者千虑必有一失.同样的道理,计算机的世界也是不完美的,异常情况随时都会发 ...

  3. C++异常之三 异常处理接口声明

    异常处理接口声明 1 一般为了方便程序员阅读代码,提高程序的可读性,会将函数中的异常类型声明至函数头后方,不用一行一行的找抛出内容: 2 这里要注意一点,这属于C++的标准语法,但在VS中这个操作不被 ...

  4. JAVA之旅(十)——异常的概述,Try-Catch,异常声明Throws,多异常处理,自定义异常,Throw和Throws的区别

    JAVA之旅(十)--异常的概述,Try-Catch,异常声明Throws,多异常处理,自定义异常,Throw和Throws的区别 不知不觉,JAVA之旅这个系列已经更新到第十篇了,感觉如梦如幻,时间 ...

  5. java异常处理 throw RuntimeException时不需要同时方法中声明抛出throws 异常等待调用者catch进行捕获 子父类异常问题

    package com.swift.exception1; public class Demo_Exception { public static void main(String[] args) { ...

  6. “全栈2019”Java异常第十五章:异常链详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  7. “全栈2019”Java异常第十三章:访问异常堆栈跟踪信息

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  8. “全栈2019”Java异常第一章:什么是异常?

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  9. C++异常之七 标准库里的异常类

    标准库里的异常类 C++标准提供了一组标准异常类,这些类以基类 Exception 开始,标准程序库抛出的所有异常,都派生于该基类,这些类构成如图所示的异常类的派生继承关系,该基类提供一个成员函数 w ...

随机推荐

  1. JavaScript Window History

    window.history 对象包含浏览器的历史. Window History window.history对象在编写时可不使用 window 这个前缀. 为了保护用户隐私,对 JavaScrip ...

  2. SpringMVC之Ajax与Controller交互

    前面学习了拦截器,通过拦截器我们可以拦截请求,做进一步处理之后再往下进行,这里我们使用Ajax的时候会有一个问题就是会把js.css这些静态资源文件也进行了拦截,这样在jsp中就无法引入的静态资源文件 ...

  3. 建立自己的git服务器

    需求情景 就像金山快盘同步盘那样, 在开发环境windows 10和部署环境Ubuntu server 14.04之间建立同步关系.比如windows端多了一个a.txt文件,你推送后,Ubuntu端 ...

  4. Java经典设计模式之七大结构型模式(附实例和详解)

    博主在大三的时候有上过设计模式这一门课,但是当时很多都基本没有听懂,重点是也没有细听,因为觉得没什么卵用,硬是要搞那么复杂干嘛.因此设计模式建议工作半年以上的猿友阅读起来才会理解的比较深刻.当然,你没 ...

  5. 使用spark ml pipeline进行机器学习

    一.关于spark ml pipeline与机器学习 一个典型的机器学习构建包含若干个过程 1.源数据ETL 2.数据预处理 3.特征选取 4.模型训练与验证 以上四个步骤可以抽象为一个包括多个步骤的 ...

  6. com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field 异常

    分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519) 1.1.1. 前言 近期在使用ObjectMapper对象将jso ...

  7. Android Multimedia框架总结(十)Stagefright框架之音视频输出过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52560012 前言:上篇文中最后 ...

  8. FFmpeg的HEVC解码器源代码简单分析:解码器主干部分

    ===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...

  9. 有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列。对于1<=i,j<=k,求k个最小的(ai+bj)。要求算法尽量高效。

    有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列.对于1<=i,j<=k,求k个最小的(ai+bj).要求算法尽量高效. int * ...

  10. time,gettimeofday,clock_gettime

    time()提供了秒级的精确度 1.头文件 <time.h> 2.函数原型 time_t time(time_t * timer) 函数返回从UTC1970-1-1 0:0:0开始到现在的 ...