[转]C++异常处理 2

}
}

void main(){
ExceptionClass e("Test");
try{
e.mythrow();
}
catch(...)
{
cout<<”*********”<<endl;
}
}
这是输出信息:
Construct Test
Construct my throw
Destruct my throw
****************
Destruct my throw (这里是异常处理空间中对异常类的拷贝的析构)
Destruct Test
======================================
不过一般来说我们可能更习惯于把会产生异常的语句和要throw的异常类分成不同的类来写,下面的代码可以是我们更愿意书写的:
………..
class ExceptionClass{
public:
ExceptionClass(const char* name="Exception Default Class"){
cout<<"Exception Class Construct String"<<endl;
}
~ExceptionClass(){
cout<<"Exception Class Destruct String"<<endl;
}
void ReportError(){
cout<<"Exception Class:: This is Report Error Message"<<endl;
}
};

class ArguClass{
char* name;
public:
ArguClass(char* name="default name"){
cout<<"Construct String::"<<name<<endl;
this->name=name;
}
~ArguClass(){
cout<<"Destruct String::"<<name<<endl;
}
void mythrow(){
throw ExceptionClass("my throw");
}
};

_tmain()
{
ArguClass e("haha");
try {
e.mythrow();
}
catch(int)
{
cout<<"If This is Message display screen, This is a Error!!"<<endl;
}
catch(ExceptionClass pTest)
{
pTest.ReportError();
}
catch(...){
cout<<"***************"<<endl;
}
}
输出Message:
Construct String::haha
Exception Class Construct String
Exception Class Destruct String
Exception Class:: This is Report Error Message
Exception Class Destruct String
Destruct String::haha

使用异常规格编程
如果我们调用别人的函数,里面有异常抛出,用去查看它的源代码去看看都有什么异常抛出吗?这样就会很烦琐。比较好的解决办法,是编写带有异常抛出的函数时,采用异常规格说明,使我们看到函数声明就知道有哪些异常出现。

异常规格说明大体上为以下格式:

void ExceptionFunction(argument…) throw(ExceptionClass1, ExceptionClass2, ….)

所有异常类都在函数末尾的throw()的括号中得以说明了,这样,对于函数调用者来说,是一清二楚的。

注意下面一种形式:

void ExceptionFunction(argument…) throw()

表明没有任何异常抛出。

而正常的void ExceptionFunction(argument…)则表示:可能抛出任何一种异常,当然,也可能没有异常,意义是最广泛的。

异常捕获之后,可以再次抛出,就用一个不带任何参数的throw语句就可以了。
构造和析构中的异常抛出
这是异常处理中最要注意的地方了

先看个程序,假如我在构造函数的地方抛出异常,这个类的析构会被调用吗?可如果不调用,那类里的东西岂不是不能被释放了?

#include <iostream.h>
#include <stdlib.h>

class ExceptionClass1
{
char* s;
public:
ExceptionClass1(){
cout<<"ExceptionClass1()"<<endl;
s=new char[4];
cout<<"throw a exception"<<endl;
throw 18;
}
~ExceptionClass1(){
cout<<"~ExceptionClass1()"<<endl;
delete[] s;
}
};

void main(){
try{
ExceptionClass1 e;
}catch(...)
{}
}

结果为:

ExceptionClass1()
throw a exception

在这两句输出之间,我们已经给S分配了内存,但内存没有被释放(因为它是在析构函数中释放的)。应该说这符合实际现象,因为对象没有完整构造。

为了避免这种情况,我想你也许会说:应避免对象通过本身的构造函数涉及到异常抛出。即:既不在构造函数中出现异常抛出,也不应在构造函数调用的一切东西中出现异常抛出。

但是在C++中可以在构造函数中抛出异常,经典的解决方案是使用STL的标准类auto_ptr。
其实我们也可以这样做来实现:在类中增加一个 Init(); 以及 UnInit();成员函数用于进行容易产生错误的资源分配工作,而真正的构造函数中先将所有成员置为NULL,然后调用 Init(); 并判断其返回值/或者捕捉 Init()抛出的异常,如果Init();失败了,则在构造函数中调用 UnInit(); 并设置一个标志位表明构造失败。UnInit()中按照成员是否为NULL进行资源的释放工作。

那么,在析构函数中的情况呢?我们已经知道,异常抛出之后,就要调用本身的析构函数,如果这析构函数中还有异常抛出的话,则已存在的异常尚未被捕获,会导致异常捕捉不到。

标准C++异常类
C++有自己的标准的异常类。

①一个基类:
exception 是所有C++异常的基类。
class exception {
public:
exception() throw();
exception(const exception& rhs) throw();
exception& operator=(const exception& rhs) throw();
virtual ~exception() throw();
virtual const char *what() const throw();
};

② 下面派生了两个异常类:

logic_erro 报告程序的逻辑错误,可在程序执行前被检测到。

runtime_erro 报告程序运行时的错误,只有在运行的时候才能检测到。

以上两个又分别有自己的派生类:

③ 由logic_erro派生的异常类

domain_error 报告违反了前置条件

invalid_argument 指出函数的一个无效参数

length_error 指出有一个产生超过NPOS长度的对象的企图(NPOS为size_t的最大可表现值

out_of_range 报告参数越界

bad_cast 在运行时类型识别中有一个无效的dynamic_cast表达式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值