一、基本的异常处理
-
异常处理机制:暂缓问题处理,不在当前函数中处理,在他调用者中处理(例:函数一调用了函数二,函数二也调用了函数三,----函数n中throw出了异常,我们在前面任何一个函数中处理都可以。)
-
什么是异常,任何东西都可以认为是异常,错误只是异常的一种
-
异常一旦被抛出,不做处理,如果引发异常,会调用默认abort终止程序
-
捕获和处理异常
-
throw 抛出异常,(可以理解为返回值,值是任何类型都可以,使我们处理异常一个参照)
-
try(检查,捕获)和catch(处理异常)(注意:catch之后还有正常语句的话,会继续进行。)
//try 与catch必须是一起出现,并且他们{}不能省略 try { //正常需要检查是否存在异常代码 } catch(类型) //理解为switch中case语句 { //处理是根据抛出数据类型决定如何处理 } //一个try可以对应多个catch try { //... } catch(int) { } catch(double) { } catch(string) { } //catch和if else_if 执行机制是一样的,只能执行一个匹配项
//删减符 ... 任何类型异常都捕获
-
catch(...)
不存在异常的描述//写在函数后面
-
throw ()
-
noexcept
void print() throw() { cout << "当前函数不存在抛出异常操作" << endl; } void printData() noexcept { cout << "新的描述:不存在抛出异常" << endl; //throw 0; 编译不过,一旦说明没有异常操作,就不能抛出 }
二、异常处理中的传参
-
catch(int a) //隐藏一个传参操作
-
想要处理抛出字符串的异常处理,注意一下string类型与const char* 类型的区别
-
也可以抛出自己类的对象
#include <iostream> #include <string> using namespace std; class Error { public: Error(const char* str = "未知错误") :str(str) {} const char* what()const { return str.c_str(); } protected: string str; }; int divisor(int a, int b) { if (b == 0) throw "除数不能为0"; if(b==1) throw "除数不能为1"; if(b==2) throw string("除数不能为2"); return a / b; } void insertArray(int array[], int* curNum, int posData,int maxLength) { if (*curNum >= maxLength) //3>=3 { throw Error("数组下标溢出!"); } //0 1 2 array[*curNum] = posData; //array[3]=3 (*curNum)++; } int main() { try { divisor(1, 0); } catch (const char* str) //str= "除数不能为零"; { cout << str << endl; } try { divisor(1, 2); } catch (string str) { cout << str << endl; } try { int array[3] = { 0,0,0 }; int curNum = 0; for (int i = 0; i < 4; i++) { insertArray(array, &curNum, i, 3); } } catch (Error str) //利用catch是传参的。 { cout << str.what() << endl; } return 0; }
三、标准库中的异常
- exception是基类,其余均是它的派生类
<exception>有what()方法。使用例子:(在try里面系统会自动跳出一个bad_alloc对象)
bad_typeid、bad_cast、bad_alloc、ios_base::failure、out_of_range 都是 exception 类的派生类。C++ 程序在碰到某些异常时,即使程序中没有写 throw 语句,也会自动拋出上述异常类的对象。这些异常类还都有名为 what 的成员函数,返回字符串形式的异常描述信息。使用这些异常类需要包含头文件 stdexcept或者exception。(头文件
#include <exception>
int main()
{
try
{
while (1)
{
int* p = new int[1024 * 1024 * 10];
}
}
catch (bad_alloc& object)
{
cout << object.what() << endl;
}
return 0;
}
自己写一个exception还原标准库中的代码:
class Exception
{
public:
Exception(const char* ptr = "UNKNOW") :ptr(const_cast<char*>(ptr)) {}
virtual const char* what() const
{
return ptr;
}
protected:
char* ptr;
};
class Bad_alloc :public Exception
{
public:
Bad_alloc(const char* _Message = "bad exception") :Exception(_Message) {}
protected:
};
class Run_time :public Exception
{
public:
Run_time(const char* _Message = "run_time error") :Exception(_Message) {}
protected:
};
注意:继承的子类,父类的属性是要用父类的构造函数的。然后子类给Exception赋值,调用的是Exception中的what方法(如果不给Exception初始化,what中return的就是默认的UNKNOW字符串常量了)
其过程类似于如下代码:
class A
{
public:
A(int num):num(num){}
int returna()
{
return num * 10;
}
protected:
int num;
};
class B:public A
{
public:
B(int num,int b):A(num),b(b){}
protected:
int b;
};
int main()
{
B b(10, 11);
cout << b.returna() << endl;
return 0;
}
输出:100
四、自定义类的异常
(写一个类或者派生类适用于多个错误情况)
①自己写的异常类 class Error
class Error
{
public:
Error(const char* str):str(const_cast<char*>(str)){}
const char* what()const
{
return str;
}
protected:
char* str;
};
int divide(int a, int b)
{
if (b == 0)
throw Error("分母不可以为0");
return (a / b);
}
void testError()
{
try
{
int result = divide(112, 0);
}
catch (Error&p)
{
cout << p.what() << endl;
}
}
②继承标准库中的异常类,通过重写what方法 :class MyException
//继承标准库中的异常类,通过重写what方法 :class MyException
class MyException :public exception
{
public:
MyException(string str) :exception(str.c_str()) {};
};
void insertArray(int cap)
{
if (cap >= 5)
throw MyException("数组已经满了");
cout << "插入成功" << endl;
}
void testMyException()
{
try
{
insertArray(6);
}
catch (MyException& d)
{
cout << d.what() << endl;
}
}