关闭

C++异常处理 - 栈解旋,异常接口声明,异常类型和异常变量的生命周期

标签: 异常栈解旋异常接口声明生命周期
1123人阅读 评论(0) 收藏 举报
分类:

栈解旋(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;
}

0
0
查看评论

C++高效获取函数调用堆栈

  • 2011-07-24 17:23
  • 112KB
  • 下载

lua调用C++函数崩溃时,查看lua的调用栈信息 (特别适用于tolua++)

cocos2d-x这个开源引擎目前在移动开发领域挺火,我用了一阵子,非常喜欢它的lua绑定,一旦理解了其工作机制,用起来相比C++有不同的感受。         但是想要用好lua脚本,实在不是件容易的事情。要让lua绑定变得非常好用,可能依然需要大量工...
  • q277055799
  • q277055799
  • 2014-05-25 12:51
  • 777

c++异常处理,异常声明,捕获异常

 C++捕获异常的一些规则: 1.    非MFC的c++异常应该用过引用来捕获。使用引用来捕获异常不需要删除c++异常对象。因为使用引用捕获的异常对象会在栈中传递。而且保持了多态性,使得你捕获的异常正是你抛出的异常对象。使用指针捕获异常的话,需要你...
  • bichenggui
  • bichenggui
  • 2009-11-16 17:30
  • 4802

C++11中stoi函数的异常处理

stoi当字符串不符合规范时,会抛出异常,所以你应该捕获异常来做。 #include #include #include using namespace std; int main() { std::string y = "2536475869463342210021012...
  • u014694994
  • u014694994
  • 2018-01-16 14:35
  • 56

C++--异常(Exceptions)

C++--异常(Exceptions)     1.概况          异常即程序运行是发生错误。在C语言中通常用返回值来判断异常,返回值可以是bool型,用true表示无异常,false...
  • u011763045
  • u011763045
  • 2014-03-23 00:13
  • 1171

c++ 堆栈解退的概念

刚在看书的时候,了解到了一个很酷的概念——堆栈解退。 也就是使用try块时,try块没有直接调用引发异常的函数,而是调用了对引发异常的函数进行调用的函数,当会引发异常的函数发生异常时,程序的跳转,堆栈的变化锁所涉及到的一项技术。 它具有释放堆栈中自动变量,调用堆栈中自动类对象析构函数的能力,有了它...
  • daye704
  • daye704
  • 2016-02-19 17:08
  • 401

C++ 异常处理(三) exception类

1,exception 头文件: #include C++ 可以把它用作其它异常类的基类。 代码可以引发exception异常,也可以把exception用作基类, 在从exception派生而来的类中重新定义一个名为what()的虚拟成员函数, 它返回一个字符串,该字符串随实现而异。...
  • u010921682
  • u010921682
  • 2015-04-03 01:41
  • 4445

C/C++异常处理的对比

本文主要介绍C异常处理与C++异常处理的区别。 包括errno、signal、nonlocal goto、异常的捕获、异常规格说明(exception specification)、标准异常对象等。
  • yeming81
  • yeming81
  • 2010-06-16 00:19
  • 4699

unity异常处理的方法

转自:http://www.cnblogs.com/1-2-3/archive/2009/11/18/unity-aop-exception.html 摘要   使用 unity 处理异常的方法可能会与你的直觉不符。本文将给出正确的处理方法,并简单剖析Unity这部分源代码。 处理异常...
  • bsmmaoshenbo
  • bsmmaoshenbo
  • 2016-04-28 11:32
  • 1200

异常类型_异常变量的生命周期

传智扫地僧课程学习笔记。 这是原始的错误处理方式, int my_strcpy( char *to, char *from) { if( from == NULL ) { return 1; } if( to == NULL ) { return 2; } if( (*fr...
  • qq_18973645
  • qq_18973645
  • 2017-01-15 12:40
  • 81
    个人资料
    • 访问:421729次
    • 积分:8188
    • 等级:
    • 排名:第2968名
    • 原创:401篇
    • 转载:30篇
    • 译文:11篇
    • 评论:87条
    博客专栏