什么是异常?
异常:
异常这个概念可能会有一些陌生,但是str.at(i)我们并不陌生,当i值越界时就会产生一个异常语句:terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::at: __n (which is 7) >= this->size() (which is 5),此时会终止程序,让程序运行更安全。异常处理机制允许程序在发生错误时保持控制流,能够清理资源并继续执行或安全地终止程序。
报错:
相比于异常而言,报错则是我们的老朋友了,还记得恐怖的“段错误”带来的恐惧吗?报错通常指的是程序在编译时或运行时遇到的严重问题,可能导致程序崩溃或无法继续执行。报错可以是语法错误、链接错误或运行时错误(如访问非法内存)。
总结来说,异常是可以被捕获和处理的错误情况,而报错通常是更严重的问题,可能导致程序无法继续运行。异常处理提供了一种优雅的方式来管理错误,而报错则需要在代码编写和调试阶段加以注意。
一、异常的处理方式
1.抛出异常
关键字:throw
可以throw关键字在代码块的任何位置抛出异常,通常在达到一些预设的逻辑问题时进行抛出,异常对象在抛出后如果没有捕获,会逐层向上传递,直到主函数。如果主函数中也没有正确捕获异常对象,则程序运行终止。
#include <iostream>
using namespace std;
double divide(double a,double b)
{
if(b == 0)
{
throw ;//当b为零时,抛出异常
}
return a/b;
}
int main()
{
cout << divide(1,0) << endl;
return 0;
}
此时代码运行后会出现:terminate called without an active exception 提示运行出现异常,程序终止。
2.捕获异常
使用try-catch块捕获异常。
try块负责执行可能抛出异常的代码,catch块用来匹配异常类型:
- 如果catch不能正确匹配类型,相当于没有捕获成功,异常对象继续向上传递。
- 如果catch能正确匹配类型,捕获成功,此时直接跳转到catch块执行代码,catch块执行完毕后try-catch块结束,执行外层的代码。
#include <iostream> using namespace std; double divide(double a,double b) { if(b == 0) { throw "除数不能为0"; } return a/b; } int main() { // 捕获成功 try { cout << divide(1,0) << endl; }catch(const char* e) //捕获的异常的类型 { cout << "捕获成功!" << e << endl; } return 0; }
此时会打印出捕获的异常:“除数不能为零”(注意:这是const char*类型)。程序终止。
二、标准异常
使用这些标准异常需要引入头文件 #include <stdexcept>
三、自定义异常
实际开发中由于C++异常机制不完善,如果要使用异常通常需要扩展标准异常家族,此时可以自定义异常类,继承标准异常类型。
#include <iostream>
#include <stdexcept> // 标准异常
using namespace std;
/**
* @brief The ZeroException class
* 自定义异常类继承标准异常类
*/
class ZeroException:public exception
{
public:
// throw()表示异常规格说明
// 告诉编译器此函数不会抛出异常
const char* what() const throw() //异常函数
{
return "除数不能为0";
}
};
double divide(double a,double b)
{
if(b == 0)
{
throw ZeroException();
}
return a/b;
}
int main()
{
// 捕获成功
try
{
cout << divide(1,0) << endl;
}catch(const ZeroException& e)
{
cout << "捕获成功!" << e.what() << endl;
}
cout << "主函数执行完毕" << endl;
return 0;
}
此时当产生异常时,捕获的就是自己定义的异常类型。