异常处理机制
异常
是一种程序控制机制,与函数机制互补
函数是一种以栈结构
展开的上下函数衔接的程序控制系统,异常是另一种控制结构,它可以在出现“意外”时中断当前函数,并以某种机制(类型匹配)回馈给隔代的调用者相关的信息
传统错误处理机制
-
通过函数返回值来处理错误
-
#include <stdio.h> #include <stdlib.h> #include <string> #define BUFSIZE 1024 //实现文件的二进制拷贝 int copyfile2(const char* dest, const char* src) { FILE* fp1 = NULL, * fp2 = NULL; //rb 只读方式打开一个二进制文件,只允许读取数据 fopen_s(&fp1, src, "rb"); if (fp1 == NULL) { //return -1; throw new std::string("文件不存在"); } //wb 以只写的方式打开或新建一个二进制文件,只允许写数据 fopen_s(&fp2, dest, "wb"); if (fp2 == NULL) { //return -2; throw - 2; } char buffer[BUFSIZE]; int readlen, writelen; while ((readlen = fread(buffer, 1, BUFSIZE, fp1))>0) { writelen = fwrite(buffer, 1, readlen, fp2); if (readlen != writelen) { //return -3; throw - 3; } } fclose(fp1); fclose(fp2); return 0; } int copyfile1(const char* dest, const char* src) { return copyfile2(dest, src); } int main(void) { int ret = 0; //ret = copyfile1("E:/奇牛培训/学习笔记/异常处理机制/dest.txt", "E:/奇牛培训/学习笔记/异常处理机制/src.txt"); try { ret = copyfile1("E:/奇牛培训/学习笔记/异常处理机制/dest.txt", "E:/奇牛培训/学习笔记/异常处理机制/src.txt"); } catch(int error){ //出现异常就会直接抛出来,不需要一层一层地递归返回值 printf("出现异常啦;%d\n",error); }catch (std::string *error) { printf("出现字符串异常:%s\n", error->c_str()); } /* if (ret != 0) { switch (ret) { case -1: printf("打开源文件失败\n"); break; case -2: printf("打开目标文件失败\n"); break; case -3: printf("拷贝文件时出错\n"); break; default: printf("出现未知情况\n"); break; } } */ }
异常处理基本语法
"异常发生第一现场,抛出异常"
void function(){
//...
throw 表达式
//...
}
"在需要关注异常地地方,捕捉异常"
try{
//程序
function();
//程序
}catch(异常类型声明){
//...异常处理代码...
}catch(异常类型声明){
//...异常处理代码...
}catch(...){
//类型太多,用...来表示
}
-
通过
throw操作
创建一个异常对象并抛出 -
在需要捕捉异常地地方,将可能抛出异常地程序段嵌在try块之中
-
按正常地程序
顺序执行到try语句
,然后执行try块{}
内地保护段 -
如果在保护段期间没有引起异常,那么跟在try块后的catch子句就不执行
-
catch子句按其在
try块后出现的顺序
被检查,匹配的catch子句将捕获并按catch子句中的代码处理异常(或继续抛掷异常) -
如果没有找到匹配,则缺省功能是
调用abort
终止程序。 -
处理不了地异常,我们可以在catch的
最后一个分支
,使用throw语法继续向调用者throw
异常接口声明
1、对于异常接口的声明,在函数声明中"列出可能抛出的所有异常类型"
2、如果"没有"包含异常接口声明,此函数可以"抛出任何类型"的异常
3、如果函数声明中有列出可能抛出的"所有异常类型",那么抛出其他类型的异常可能"导致程序终止"
4、如果一个函数"不想抛出"任何异常,可以使用 throw() 声明
实现文件的二进制拷贝
int copyfile2(const char* dest, const char* src) throw(float,string*,int);
异常类型和生命周期
-
throw基本类型:
-
和函数返回传值是一样的
-
-
throw字符串类型:
-
实际抛出的指针,而且,修饰指针的const也要严格进行类型匹配
-
-
throw 类对象类型异常
-
最佳的方式是使用引用类型捕捉,抛出匿名对象
当然,如果是动态分配的对象,直接抛出其指针
引用和普通的形参传值不能共存
-
try{//保护段 //printf("开始执行 copyfile1...\n"); ret = copyfile1("c:/test/dest.txt", "c:/test/src.txt"); //printf("执行 copyfile1 完毕\n"); }catch(ErrorException error){//不能共存 普通 printf("出现异常啦!捕捉到 ErrorException 类型 id: %d\n", error.id); }catch(ErrorException &error){//不能共存 引用 //error.id = 2; printf("出现异常啦!捕捉到 ErrorException &类型 id: %d\n", error.id); }catch(ErrorException *error){ printf("出现异常啦!捕捉到 ErrorException *类型 id: %d\n", error->id); delete error; }catch(...){ printf("没捉到具体的异常类型\n"); }
-
继承与异常
异常也是类
,我们可以创建自己的异常类,在异常中可以使用(虚函数,派生,引用传递和数据成员等
)
#include <iostream>
using namespace std;
/*
案例:设计一个数组类容器 Vector,重载[]操作,数组初始化时,对数组的个数进行有效检查
1)index<0 抛出异常errNegativeException
2)index = 0 抛出异常 errZeroException
3)index>1000抛出异常errTooBigException
4)index<10 抛出异常errTooSmallException
5)errSizeException类是以上类的父类,实现有参数构造、并定义virtual void printError()输出错误。
*/
class Vector {
public:
Vector(int size = 128);//构造函数
Vector(const Vector& object);//拷贝构造函数
int getLength();//获取内部储存的元素个数
int& operator[](int index);
~Vector();
private:
int* m_base;
int m_len;
};
class errSizeException {
public:
errSizeException(int size) {
m_size = size;
}
virtual void printError() {
cout << "size: " << m_size << endl;
}
protected:
int m_size;
};
class errNegativeException :public errSizeException{
public:
errNegativeException(int size) :errSizeException(size) {
}
virtual void printError() {
cout << "errNegativeException size: " << m_size << endl;
}
};
class errZeroException :public errSizeException {
public:
errZeroException(int size) :errSizeException(size) {
}
virtual void printError() {
cout << "errZeroException size: " << m_size << endl;
}
};
class errTooBigException :public errSizeException {
public:
errTooBigException(int size) :errSizeException(size) {
}
virtual void printError() {
cout << "errTooBigException size: " << m_size << endl;
}
};
class errTooSmallException :public errSizeException {
public:
errTooSmallException(int size) :errSizeException(size) {
}
virtual void printError() {
cout << "errTooSmallException size: " << m_size << endl;
}
};
Vector::Vector(int len){
if(len < 0){
throw errNegativeException(len);
}else if(len == 0){
throw errZeroException(len);
}else if(len > 1000){
throw errTooBigException(len);
}else if(len < 10){
throw errTooSmallException(len);
}
m_len = len;
m_base = new int[len];
}
Vector::Vector(const Vector& object)
{
}
int Vector::getLength()
{
return m_len;
}
int& Vector::operator[](int index)
{
// TODO: 在此处插入 return 语句
return m_base[index];
}
Vector::~Vector()
{
if (m_base) delete[]m_base;
m_len = 0;
}
int main() {
try {
Vector v(5);
}
catch (errSizeException& err) {
err.printError();
}
/*catch (errNegativeException& error) {
cout << "errNegativeException..." << endl;
}
catch (errZeroException &error) {
cout << "errZeroException..." << endl;
}
catch (errTooBigException &error) {
cout << "errTooBigException..." << endl;
}
catch (errTooSmallException &error) {
cout << "errTooSmallException..." << endl;
}*/
/*for (int i = 0; i < v.getLength(); i++) {
v[i] = i + 10;
printf("v[i]: %d\n", v[i]);
}*/
}
标准程序库异常
#include <iostream>
#include <exception>
#include <stdexcept>
using namespace std;
class Student {
public:
Student(int age) {
if (age > 249) {
throw out_of_range("年龄太大了,你是外星人吗?");
}
m_age = age;
m_space = new int[1024 * 1024*100];
}
private:
int m_age;
int* m_space;
};
int main() {
try {
for(int i=1;i<1024;i++)
Student * xiao6lang = new Student(18);
}
catch (out_of_range &e) {
cout << "捕捉到一只异常:" << e.what() << endl;
}
catch (bad_alloc& e) {
cout << "捕捉到动态内存分配的异常:" << e.what() << endl;
}
return 0;
}