C++异常的使用

1. 为什么C++引进了异常概念

C语言中处理错误的方法有:

  1. 终止程序,如assert。但是因为某个函数出错而让整个程序终止,这样用户是难以接受的
  2. 返回错误码,缺陷:需要程序员自己去查找对应的错误,维护成本高
  3. C 标准库中setjmp和longjmp

为了解决C语言这些不太友好的错误处理机制,C++才引入了异常,异常也是一种处理错误的方法:当一个函数遇到错误时会抛出异常,让函数的直接或间接调用者去处理

2. 异常的使用

  • 抛异常
    throw 被抛出的对象
  • 捕获异常
    catch(捕获异常的类型)
    catch需要与try语句搭配
  • try
    try{可能出现异常的语句}
    try后面常跟着一个或多个catch块,try中的代码常称为保护代码

3. 异常的处理流程

  1. 因为被抛出的对象的生命周期是不知道的,所以被抛出的实际上是异常对象的拷贝
  2. 当异常对象被抛出后,退出当前函数栈,返回到上一层函数当中,依次向下寻找匹配的catch块
  3. 如果找到了匹配的catch块,则会执行catch块中的异常处理方法,如果没有找到,则会向将异常抛出给上一层函数。特别的,如果main函数中的异常没有被处理则会报错
  4. catch(…)可以捕获任意类型的异常
  5. 可以抛出的派生类对象,使用基类捕获(实际运用中常采用这种方法)
  6. 处理完异常后会跳过其他catch块执行后面的语句

写一个代码演示一下:

int Division(int left, int right) {
	if (right == 0) {
		throw std::string("除数为0");
	}
	return left / right;
}

void Func(int left, int right)
{
	int* array = new int[10];
	try {
		cout << Division(left, right) << endl;
	}
	catch (std::string &s) {
		throw s;
	}
	catch (...)
	{
		cout << "delete []" << array << endl;
		delete[] array;
		throw;
	}
	cout << "delete []" << array << endl;
	delete[] array;
}

int main() {
	int left, right;
	std::cin >> left >> right;
	try {
		Func(left, right);
	}
	catch (std::string s) {
		cout << s << endl;
	}
	catch (...) {
		throw;
	}
	return 0;
}

Division函数抛出异常后,Func中的catch对该异常进行捕获,并执行catch语句块,该语句又抛出了一个异常给main函数处理,main函数处理完后程序退出,
在这过程中并没有释放array的空间

4. 异常安全

  • 在构造函数中抛出异常,可能会导致对象不完整或没有完全初始化
  • C++中异常经常会导致资源泄漏的问题,比如在析构函数中抛异常导致资源没有释放完全,在new和delete中抛出了异常,导致内存泄漏,在lock和unlock之间抛出了异常导致死锁

5. 异常规范

  1. 函数名 throw(类型表),列出这个函数可能抛掷的所有异常类型
  2. 函数的后面接throw(),表示函数不抛异常
  3. 若无异常接口声明,则此函数可以抛掷任何类型的异常

注:即使函数后面接了throw(),函数也可以抛异常,所以这只是一种编程规范

你可能感兴趣的:(C++学习)