C++学习笔记day49—–C++98-异常处理

  • Post author:
  • Post category:其他



C++中的异常处理


关键字 throw、try、catch

#include <iostream>
using namespace std;
int main(void){
    try{
        char *p = new char[0xffffffff];
    }
    catch(exception &ex){
        cout << ex.what() << endl;
        return -1;
    }
    return 0;
}

程序员在可能会出现问题的代码后通过throw关键字将异常抛出,可以抛出一个基本类型的值,也可以抛出一个对象。

在包含可能抛出异常的代码外,使用try关键字和其作用范围对可能出现异常的代码进行包含。

使用catch捕获抛出的异常,在catch的代码块中处理异常。

在运行过程中如果真的抛出了异常,并且有多个catch语句,编译器会从自上而下的去匹配每个catch的参数类型。由于存在向上造型,所以抛出的子类异常对象时,基类的catch在子类之前,那么就会被基类类型的catch捕获。

C++标准库提供了一个exception的类,标准库的所有异常,都是它的子类。

建议程序员自定义的错误类继承exception类,这样,只需要写一个catch语句,通过向上造型的原则,就可以捕获所有类类型的错误对象。

——————————————-

二十四、异常

1 程序开发中常见的错误

1) 语法错误

2) 逻辑错误(GDB)

3) 功能错误

4) 设计缺陷

5) 需求不符

6) 环境异常

7) 操作不当

2 传统C的错误处理机制

1) 通过返回值表示错误

优点:函数调用过程中,所有的局部对象都能正确被析构,不会内存泄露

缺点:错误处理流程比较复杂,需要逐层判断,代码臃肿

2) 通过远程跳转处理错误

优点:不需要逐层判断,一步到位的处理错误,代码精炼

确定:函数调用路径中的局部对象失去被析构机会,形成内存泄露

3 C++异常机制

结合两种传统错误处理机制的优点,同时避免它们的缺点,在形式上实现一步到位的错误处理,同时保证所有的局部对象得到正确析构。

4 异常语法

1) 异常抛出

throw 异常对象;

注:异常对象可以是基本 类型也可以是类类型

2) 异常捕获

try{

//可能引发异常的语句

new

func();



}

catch(异常类型1){

针对异常类型1的处理

}

catch(异常类型2){

针对异常类型2的处理

}

catch(异常类型3){

针对异常类型3的处理

}

catch(…){

针对其他异常类型的处理

}

注:catch子句根据异常对象的类型子上而下顺序匹配,而不是最有匹匹配;因此对子类类型的异常捕获不要放在对基类类型的异常捕获后面,否则前者将被后者提前截获。(向上造型)

5 函数的异常说明

1) 语法

返回类型 函数名(性餐表)throw(异常类型表){}

//throw(int,FileError),这个函数可能抛出int,FileError类型的异常

void func(void) throw(int,FileError) {}

注:函数的异常说明只是一种承诺,不是严格的语言的要求,表示该函数所抛出的异常不会超出说明的类型范围;但是如果抛出异常说明意外的其他类型,该异常无法被正常捕获,而会被系统捕获到,导致进程的终止。

2) 函数异常说明两种极端形式

–>不写异常说明,表示可以抛出任何异常

–>空异常说明,throw,表示不会抛出任何异常

3) 如果函数的生命和定义分开书写,要保证异常说明的类型一致,但是前后顺序无所谓。

注:补充虚函数覆盖的条件

4) 如果基类中的虚函数带有异常说明,那么该函数在子类中的覆盖版本不能说明比基类版本抛出更多的异常类型,否则将因为”放松throw”的限定,导致编译失败。

5) 标准异常类exception

class exception

{

public:

exception() _GLIBCXX_USE_NOEXCEPT { }

virtual ~exception() _GLIBCXX_USE_NOEXCEPT;

/** Returns a C-style character string describing the general cause

* of the current error. */

virtual const char* what() const _GLIBCXX_USE_NOEXCEPT;

};

6 构造函数和析构函数中的异常

1) 构造函数可以抛出异常,但是对象将会不完整构造,这样的对象,析构函数是不会执行的。所以在构造函数抛出异常之前,应该手动的销毁所有在异常产生之前分配的动态资源。

2) 析构函数不要抛出异常。

异常类型表,是一种说明,但是改函数可以抛出其他类型的异常,编译器并不会报错。系统捕捉到这个异常之后,内核会将进程结束。

二十五、IO流

1 主要I/O流

ios

/ \

istream ostream

/ | \ / | \

istrstream ifstream iostream ofstream ostrstream

/ \

strstream fstream

2

1) 格式化函数(成员函数)

eg:

cout << 10/3.0 << endl;//3.333333

cout.

cout << 10/3.0 << endl;//

2) 流控制符(全局函数)

3 字符流I/O

include //过时

istrstream、

4 文件流

include

ifstream//读文件

ofstream//写文件

fstream//读写文件

5 二进制IO

//fwrite

ostream &ostream::write(const char *buffer,size_t num);

//fread

istream &istream::read(char *buffer,streamsize num);



版权声明:本文为displayMessage原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。