一文带你掌握C++异常处理

862 阅读4分钟

11. C++异常处理

什么是异常处理

异常: 任何事物,任何情况都可以当做异常,错误算是异常的一种

异常处理机制: 暂时性不做处理,抛出异常,留给使用者去处理

注意问题: 所有抛出的异常,必须要处理,如果不做处理,引发异常识,程序调用abort函数终止程序

异常处理基操

抛出异常: throw 抛出的东西一定一个值

检查异常:try

捕获处理异常:catch

注意点: try和catch必须一起出现,并且各自的{}不能省略

#include <iostream>
using namespace std;
int Div(int a, int b) 
{
	//正常写程序 有问题立刻处理
	//if (b == 0) 
	//{
	//	cout << "除数不能为0" << endl;
	//	return 0;
	//}
	if (b == 0)
		throw 0;			
	return a / b;
}

int main() 
{
	//Div(1, 0);   //调用abort函数终止程序
	try 
	{
		cout << "测试.....1" << endl;
		Div(1, 0);
		cout << "测试.....2" << endl;
	}
	catch (double)	   //捕获int类型异常    
	{
		cout << "double:除数不能为零" << endl;
	}
	catch (int) 
	{
		cout << "int:除数不能为零" << endl;
	}
	//error C2312: “int”: 由“int”在行 28 上捕获
	//catch (int)
	//{
		//cout << "int:除数不能为零" << endl;
	//}
	return 0;
}

没有异常

老版本: throw () 放在函数后面

新标准: noexcept放在函数后面修饰

//老版本 
int Max(int a, int b) throw() 
{
	return a > b ? a : b;
}
//新标准
int Sum(int a, int b) noexcept
{
	return a + b;
}

异常处理的传参操作

#include <iostream>
using namespace std;
void printArray(int array[], int arrayNum) 
{
	if (arrayNum < 1)
		throw 1;
	cout << "正常长度,假装打印...." << endl;
}
void searchArray(int array[], int arrayNum)
{
	if (arrayNum < 1)
		throw 2;
	cout << "正常长度,假装查找...." << endl;
}
void deleteArray(int array[], int arrayNum)
{
	if (arrayNum < 1)
		throw 3;
	cout << "正常长度,假装删除...." << endl;
}
int Div(int a, int b) 
{
	if (b == 0)
		throw string("除数不能为零");
	return a / b;
}
//抛出自己类对象:自定义异常类
class stackEmpty 
{
public:
	stackEmpty(string strInfo) :strinfo(strInfo) {}
	void print() 
	{
		cout << "error:" << strinfo << endl;
	}
private:
	string strinfo;
};
//假装入栈
void push(int a) 
{
	if (a == 0)
		throw stackEmpty("栈为空");
	cout << a << endl;
}

int main()
{
	try
	{
		int array[3] = { 1,2,3 };
		printArray(array, 3);
		searchArray(array, -1);
		deleteArray(array, 2);
	}
	catch (int value)			//int value=抛出的值 
	{
		switch (value)
		{
		case 1:
			cout << "打印异常" << endl;
			break;
		case 2:
			cout << "查找异常" << endl;
			break;
		case 3:
			cout << "删除异常" << endl;
			break;
		}
	}
	try
	{
		cout << Div(2, 1) << endl;
		cout << Div(2, 0) << endl;
	}
	catch (string& object)
	{
		cout << object << endl;
	}
	//... 表示可以捕获任何异常
	try
	{
		cout << Div(2, 0) << endl;
	}
	catch (...)                      //删减符
	{
		cout << "引发异常" << endl;
	}
	try 
	{
		push(1233);
		push(0);
	}
	catch (stackEmpty& object) 
	{
		object.print();
	}
	return 0;
}

标准库中的异常

C++ 提供了一系列标准的异常,定义在 中,我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的,如下所示:

下表是对上面层次结构中出现的每个异常的说明:

异常描述
std::exception该异常是所有标准 C++ 异常的父类。
std::bad_alloc该异常可以通过 new 抛出。
std::bad_cast该异常可以通过 dynamic_cast 抛出。
std::bad_typeid该异常可以通过 typeid 抛出。
std::bad_exception这在处理 C++ 程序中无法预期的异常时非常有用。
std::logic_error理论上可以通过读取代码来检测到的异常。
std::domain_error当使用了一个无效的数学域时,会抛出该异常。
std::invalid_argument当使用了无效的参数时,会抛出该异常。
std::length_error当创建了太长的 std::string 时,会抛出该异常。
std::out_of_range该异常可以通过方法抛出,例如 std::vector 和 std::bitset<>::operator
std::runtime_error理论上不可以通过读取代码来检测到的异常。
std::overflow_error当发生数学上溢时,会抛出该异常。
std::range_error当尝试存储超出范围的值时,会抛出该异常。
std::underflow_error当发生数学下溢时,会抛出该异常。

标准库中异常

exception类组成:
  • what方法 用来返回异常信息的字符串
#include <exception>
#include <iostream>
using namespace std;
class Error :public exception 
{
public:
    //virtual char const* what() const
    //{
    //    return "Error";
    //}
    Error() :exception("Error") {}
private:
};
void  printTest() 
{
    throw Error();
}

int main() 
{
    try 
    {
        printTest();
    }
    catch (Error& object) 
    {
        cout << object.what() << endl;
    }
	return 0;
}

引发ball_alloc异常

#include <exception>
#include <iostream>
using namespace std;
int main() 
{
	int array[3] = { 1,2,3 };
	try 
	{
		while (1)
		{
			int* p = new int[1024 * 1024];
		}
	}
	catch (bad_alloc& object) 
	{
		cout << object.what() << endl;
	}
	return 0;
}

异常处理的建议

  1. 局部控制能处理的问题,不需要异常机制
  2. 千万不要在析构函数抛出异常(作死操作)
  3. 构造函数存在问题,也不要次啊用异常机制
  4. 自己写异常类 没必要都是继承exception,可以适当根据具体问题,继承相应子类即可