您的位置:首页 > 编程语言 > C语言/C++

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

2015-07-06 17:15 555 查看
栈解旋(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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: