C++:6.3异常处理

(努力敲...)
(兴奋...)
 是否保存?

(思考ing)

 ?????

1、C++异常处理入门(try和catch)


   编译器能够保证代码的语法是正确的,但是对逻辑错误和运行时错误却无能为力,例如除数为 0、内存分配失败、数组越界等。这些错误如果放任不管,系统就会执行默认的操作,终止程序运行,也就是我们常说的程序崩溃(Crash)。




    string str = "c plus plus";
    char ch1 = str[100];  //下标越界,ch1为垃圾值
    cout<<ch1<<endl;
    char ch2 = str.at(100);  //下标越界,抛出异常
    cout<<ch2<<endl;


    at() 是 string 类的一个成员函数,它会根据下标来返回字符串的一个字符。与“[ ]”不同,at() 会检查下标是否越界,如果越界就抛出一个异常(错误);而“[ ]”不做检查,不管下标是多少都会照常访问。


    在C++中,我们可以捕获上面的异常,避免程序崩溃。捕获异常的语法为:
try{
    // 可能抛出异常的语句
}catch(异常类型){
    // 处理异常的语句
}


2、
异常既然是一份数据,那么就应该有数据类型。C++规定,异常类型可以是基本类型,也可以是标准库中类的类型,还可以是自定义类的类型。C++语言本身以及标准库中的函数抛出的异常,都是 exception 类或其子类的类型。也就是说,抛出异常时,会创建一个 exception 类或其子类的对象。


异常被捕获后,会和 catch 所能处理的类型对比,如果正好和 catch 类型匹配,或者是它的子类,那么就交给当前 catch 块处理。catch 后面的括号中给出的类型就是它所能处理的异常类型。上面例子中,catch 所能处理的异常类型是 exception,at() 函数抛出的类型是 out_of_range,out_of_range 是 exception 的子类,所以就交给这个 catch 块处理。


catch 后面的exception e可以分为两部分:exception 为异常类型,e 为 exception 类的对象。异常抛出时,系统会创建 out_of_range 对象,然后将该对象作为“实参”,像函数一样传递给“形参”e,这样,在 catch 块中就可以使用 e 了。


3、
  一个 try 后面可以跟多个 catch,异常被捕获时,先和 exception_type_1 作比较,如果异常类型是 exception_type_1 或其子类,那么执行当前 catch 中的代码;如果不是,再和 exception_type_2 作比较……依此类推,直到 exception_type_n。如果最终也没有找到匹配的类型,就只能交给系统处理,终止程序。






4、throw:抛出自己的异常


throw 是C++中的关键字,用来抛出异常。如果不使用 throw 关键字,try 就什么也捕获不到;上节提到的 at() 函数在内部也使用了 throw 关键字来抛出异常。


throw 既可以用在标准库中,也可以用在自定义的函数中,抛出我们期望的异常。throw 关键字语法为:


 
throw exceptionData;




exceptionData 是“异常数据”的意思,它既可以是一个普通变量,也可以是一个对象,只要能在 catch 中匹配就可以。


5、exception类






C++语言本身或者标准库抛出的异常都是 exception 的子类,称为标准异常(Standard Exception)。你可以通过下面的语句来匹配所有标准异常:
try{
    //可能抛出异常的语句
}catch(exception &e){
    //处理异常的语句
}
之所以使用引用,是为了提高效率。如果不使用引用,就要经历一次对象拷贝(拷贝对象时要调用拷贝构造函数)的过程。




6、 exception 类的直接派生类




logic_error 逻辑错误。


runtime_error 运行时错误。


bad_alloc 使用 new 或 new[ ] 分配内存失败时抛出的异常。


bad_typeid 使用 typeid 操作一个 NULL 指针,而且该指针是带有虚函数的类,这时抛出 bad_typeid 异常。


bad_cast 使用 dynamic_cast 转换失败时抛出的异常。


ios_base::failure io 过程中出现的异常。


bad_exception 这是个特殊的异常,如果函数的异常列表里声明了bad_exception 异常,当函数内部抛出了异常列表中没有的异常时,如果调用的 unexpected() 函数中抛出了异常,不论什么类型,都会被替换为 bad_exception 类型。


7、logic_error 的派生类 




   异常名称 说  明


length_error 试图生成一个超出该类型最大长度的对象时抛出该异常,例如 vector 的 resize 操作。


domain_error 参数的值域错误,主要用在数学函数中,例如使用一个负值调用只能操作非负数的函数。


out_of_range 超出有效范围。


invalid_argument 参数不合适。在标准库中,当利用string对象构造 bitset 时,而 string 中的字符不是 ’0’ 或 ’1’ 的时候,抛出该异常。




8、runtime_error 的派生类 


   range_error        计算结果超出了有意义的值域范围。


   overflow_error 算术计算上溢。


   underflow_error 算术计算下溢。
----------------------------------------------


#include <cstdio>
#include <cstdlib>
#include <exception>
#include <string>


class myexception : public std::exception {
public:
myexception(std::string s) : exception(s.c_str()) {


}
virtual ~myexception() {
printf("myexception's destructor\n");
}
virtual const char *what() const {
return exception::what();
}
public:
std::string _s;
};


class A {
public:
~A() {
printf("A's destructor\n");
}


};


class B {
public:
~B() {
printf("B's destructor\n");
}


};


void Func() {
A a;
printf("dasd\n");
myexception e("p is NULL");
e._s = "haha";
try{
int *p = NULL;
if (p == NULL) {
throw e;
}
}
catch (myexception &e) {
e._s = "heiheihei";
printf("%s\n", e.what());
throw;
}


printf("%s\n", e._s.c_str());


B b;
}


void Func2() {
try {
Func();
}
catch (myexception &e) {
printf("Func2 : %s\n", e._s.c_str());
throw;
}
}


int main() {
try {
Func2();
}
catch (myexception &e) {
printf("main: %s\n", e._s.c_str());
}
printf("hahah\n");


system("PAUSE");
return 0;
}


这个函数输出为:


dasd
p is NULL
myexception's destructor
A's destructor
Func2 : heiheihei
main: heiheihei
myexception's destructor
hahah


函数说明:
  
  main函数起,调用fun2(),进入fun2(),调用fun(),进入fun()后,   先创建一个A类对象a,
  ★输出dasd;
  再创建一个异常并初始化e(p is NULL),然后给_s赋值haha ;
  扔异常,在fun()的catch中接到,类型匹配,重新给_s赋值heiheihei;
  ★输出what,也就是“p is NULL”;
  扔异常,fun()里面没得接,要回到函数调用处,也就是fun2();
  回之前,要把局部变量销毁,也就是a 和 e;----------因为局部变量在栈区,所以先销毁e,在销毁a。(先来后出)所以输出★
  myexception's destructor
  A's destructor
  回到fun2();类型匹配,有得接,★打印_s---heiheihei;
  再扔,回到main 。因为在fun2()是直接引用的异常,所以不会销毁,也就不会析构。
   类型匹配,有得接,打印heiheihei,不扔了,后面没有catch接了,交给系统处理,终止程序。析构。★打印myexception's destructor
  ★打印hahaha,



























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值