C++异常机制
异常处理的初步使用
我们将可能导致异常的代码块用try语句块包含起来,我们称之为安全段,然后在其后捕获可能出现的异常。
注意:必须捕获至少一个异常,不然会出错。如果异常被捕获一次,除非再次抛出,不然就不会再被捕获了,尽管捕获代码里可能什么都没有做。一旦抛出异常,程序将会立即跳转到try语句块所对应的catch捕获代码,不会再执行try语句块剩下的语句。
#include <iostream>
#include <string>
using namespace std;
//指定所有可能抛出的类型
void fun1(const char* dest, const char* res)throw(int,string*,float) {
FILE *f1, *f2;
f1 = f2 = NULL;
fopen_s(&f1, res, "rb");//二进制只读
if (f1 == NULL) {
throw new string("源文件打开失败!");
}
fopen_s(&f2, dest, "wb");//二进制只写
if (f2 == NULL) {
throw new string("目标文件打开失败!");
}
char buffer[64];
int readsize, writesize;
while (readsize = fread(buffer, 1, 64, f1) > 0) {//有数据读出
writesize = fwrite(buffer, 1, 64, f2);
if (readsize != writesize) {
throw new string("读取文件失败!");
}
}
fclose(f1);
fclose(f2);
}
void fun2(const char* dest, const char* res) {
try {
fun1(dest, res);
}
catch(...) {//捕获任何类型的异常
throw;
cout << "fun2异常捕获" << endl;
}
}
int main(void) {
try {
cout << "异常捕获准备" << endl;
fun2("dest.txt", "res.txt");
cout << "异常捕获完成" << endl;
}
catch (int error) {
}
catch (string* error) {
printf("异常:%s", error->c_str());
}
catch (float error) {
}
return 0;
}
异常处理接口声明
- 在函数声明中列出所有可能抛出的异常类型
- 如果没有包含异常接口声明,默认可以抛出任何类型
- 不可以抛出异常接口声明中的类型,否则会报错
- 如果不想抛出任何类型,可以直接定义为空
void fun1(const char* dest,const char* res)throw(){}
异常类型的生命周期
一般来说,局部变量的生命周期会在离开函数之后马上析构,但匿名对象可以和catch中的参数一起在catch语句块结束后析构
注意事项
- throw类类型,最佳的方式就是使用引用类型捕获,抛出匿名对象。
- 如果是动态分配的内存,直接返回指针,但是要记得delete。
- 返回字符串的本质其实就是返回一个指针,其实也属于值传递。
- 引用和普通的形参类型不能共存,这点和函数调用是一样的。
异常类
异常也可以算做一个类,也就是说,我们可以直接定义一个错误的基类,然后从安全段中返回一个具体错误的子类。再从catch中捕获基类的引用,或者基类的指针,以此完成多态。
#pragma once
#include <iostream>
class abnormal {
public:
abnormal(int size) { this->size = size; }
virtual ~abnormal() {};
virtual void desc()const = 0;
protected:
int size;
};
class negativeabnormal :public abnormal {
public:
negativeabnormal(int size) :abnormal(size) {}
~negativeabnormal() {};
void desc()const override {
std::cout << "negativeabnormal!\nsize:" << size << std::endl;
}
};
class boundaryabnormal :public abnormal {
public:
boundaryabnormal(int size) :abnormal(size) {}
~boundaryabnormal() {};
void desc()const override {
std::cout << "boundaryabnormal!\nsize:" << size << std::endl;
}
};
在安全段中返回子类的对象,然后用基类引用来捕获就行了
template<typename T>
Vector<T>::Vector(int size) {
/*if (size > 0) {
this->size = size;
}
else {
this->size = 64;
}
arr = new T[this->size];*/
if (size < 0) {
this->size = 64;
throw negativeabnormal(size);
}
else if (size > BOUNDARY) {
this->size = BOUNDARY;
throw boundaryabnormal(size);
}
else {
this->size = size;
}
arr = new T[this->size];
}
try {//安全段
Vector<int> v1(100);
for (int i = 0; i != 10; ++i) {
v1[i] = i + 1;
}
for (int i = 0; i != 10; ++i) {
cout << v1[i] << " ";
}
}
catch (const abnormal& object) {
object.desc();
cout << endl;
}
标准库里的异常类
标准库里也定义了一些异常类供我们使用,比较常见的有bad_alloc和out_of_range子类的,其中bad_alloc由系统在分配空间失败时自动调用。记得要包含对应的头文件exception和stdexcept