《C++编程思想II》第一章-异常处理

来源:互联网 发布:吃鸡游戏画面优化软件 编辑:程序博客网 时间:2024/06/07 05:13

第一章   异常处理

1.1传统的错误处理

1、  使用异常处理:

(1)      错误处理代码的编写不再冗余乏味,与“正常代码”分离;

(2)      错误不能被忽略。

2、  在c语言中,有三种方法用来处理错误或异常:

(1)      使用标准库中的errno和perror();

(2)      使用罕见的信号处理系统函数signal()和raise();

(3)      使用标准c库中的非局部跳转函数setjmp()和longjmp(),其中setjmp()保存一个已知的无错误状态,一旦发生错误,则通过调用longjmp()返回到该状态。但是这二个函数并不会调用c++对象的析构函数,因此对象不会被正确的清理(当longjmp()跳转到超出析构函数的作用范围以外,行为不可预料。在这种情况下,不可能有效地从错误状态中恢复,因为程序中留下了未被清理但有不能被再次访问的对象。)

 

//c01:nonlocal.cpp

//setjmp()& longjmp

 

#ifndef NONLOCAL_HPP

#define NONLOCAL_HPP

 

#include <iostream>

#include <csetjmp>

 

using namespace std;

 

class Rainbow{

public:

   Rainbow() {cout<< "Rainbow()"<<endl; }

   ~Rainbow() {cout<<"~Rainbow()"<<endl;}

};

 

jmp_buf kansas;

 

void oz()

{

   Rainbow rb;

   for (inti = 0; i <3; ++i)

   {

      cout<< "there is no place like home "<<endl;

   }

   longjmp(kansas,47);//不一定会执行rb~Rainbow(),某些C++编译器(如vc编译器)包含了扩展的longjmp(),能够清除栈中的对象,

}

 

int test_jmp()

{

   if (setjmp(kansas) == 0)

   {

      cout<<"tornado, witch, munchkins..."<<endl;

      oz();

   }

   else{

      cout<<"Auntile Em !"

         <<"I had the strangest dream..."

         <<endl;

   }

   return 0;

}

 

3、  goto是局部跳转函数,而longjmp是非局部跳转函数,通过longjmp()程序可以返回到运行栈中任何预确定的位置。在C++中使用longjmp()的问题是它不能识别对象,尤其在跳出某个作用域的时候,它不会调用对象的析构函数。而析构函数的调用在c++中是必需的操作,因此这种方法不使用与c++。

1.2抛出异常

1、当代码出现异常,通过当前语境无法获取足够信息决定采取什么措施时,可以创建一个包含错误信息的对象并抛出当前语境,通过这种方式将错误信息发送到更大范围的语境中,叫做“抛出一个异常”。

2、抛出一个异常时,可以使用任意类型,但通常应为抛出的异常创建特定的类。

3、程序员需要为每一种不同的异常情况抛出不同类型的对象。

 

1.4捕捉异常

1、抛出异常或者由于某个原因导致一个异常被抛出的析构函数设计是不合理的,这样会导致系统调用terminate()或者用户自定义的set_terminate()退出程序。

1.5资源管理

1、为防止资源泄露,必须使用以下二种方式之一来防止“不成熟的”资源分配方式:

(1)在构造函数中捕获异常,用于释放资源;

(2)在对象的构造函数中分配资源,并且在对象的析构函数中释放资源。

1.6 标准异常

1、所有标准异常都是从exception类派生的,exception类定义在头文件<exception>中,exception类有二个主要的派生类为logic_error和runtimer_error,这二个类定义在头文件<stdexcep>中(包含<exception>头文件),用户应该从这二个类中派生新的子类,而不要用exception类作为子类。输入输出流异常类ios::failure也从exception类派生,但是它没有子类。

2、logic_error的子类:domain_error,invalid_argument, length_error, out_of_range, bad_cast, bad_typeid;

 runtime_error的子类: range_error, overflow_error, bad_alloc

1.7异常规格说明

1、异常规格说明使用关键字throw,函数可能抛出的所有可能异常的类型应该被写在throw之后的括号中,这里的函数声明如下所示:

 

void f() throw (toobig, toosmall, divzero);// 抛出三种异常

void f();//可能抛出任何异常

void f() throw(); //不抛出任何异常

0 0
原创粉丝点击