目录
概念
抛出异常(throw)
捕获异常(try - catch)
标准异常体系
自定义异常
多重捕获
粗略捕获
概念
异常提供了一种转移控制权的方式。
程序一旦出现没有经过处理的异常,就会造成程序运行崩溃。
异常处理机制可以帮助开发人员在程序发生异常时进行适当的处理,以确保程序可以正常执行或提供错误信息。
C++的异常处理通过使用 try 、catch 和 throw 关键字来实现。 try 块用于包含可能引发异常的代码,而 catch 块用于捕获并处理异常。 throw 关键字用于引发异常。
注意,在使用异常处理时,我们应该遵循以下几点:
- 只在真正需要时使用异常处理,不要滥用异常。
- 不要在循环或频繁调用的代码块中使用异常处理,以避免性能问题。
- 在 catch 块中应尽量提供详细的错误信息,以帮助调试和诊断问题。
抛出异常(throw)
使用 throw
关键字可以抛出异常。throw
关键字后面可以跟着一个表达式,该表达式的结果将被当作异常对象。
以下是一个示例,演示如何使用 throw
抛出异常:
double divide(double a, double b) {
if (b == 0) {
throw "Divide by zero exception";
}
return a / b;
}
在上述示例中,我们定义了一个 divide
函数,用于计算两个数的商。在函数内部,我们检查除数是否为零。如果除数为零,则使用 throw
关键字抛出一个字符串异常对象。
捕获异常(try - catch)
在C++中,我们可以使用 try-catch
块来捕获异常。try
块用于包含可能引发异常的代码,而catch
块用于处理捕获的异常。
以下是一个示例,演示如何使用try-catch
捕获异常:
#include <iostream>
double divide(double a, double b) {
if (b == 0) {
throw "Divide by zero exception";
}
return a / b;
}
int main() {
try {
double result = divide(10, 0);
std::cout << "Result: " << result << std::endl;
} catch (const char* error) {
std::cout << "Error: " << error << std::endl;
}
return 0;
}
在上述示例中,我们定义了一个divide
函数,用于计算两个数的商。在函数内部,我们检查除数是否为零。如果除数为零,则使用throw
关键字抛出一个字符串异常对象。
在main
函数中,我们将调用divide
函数放在一个try
块中。如果在try
块中的代码引发了异常,控制流会立即跳转到匹配的catch
块,并执行其中的代码。在这个示例中,我们使用catch (const char* error)
来捕获字符串异常对象,并在catch
块中输出错误信息。
注意,在catch
块中,我们可以使用不同类型的参数来捕获不同类型的异常对象。在上述示例中,我们使用了const char*
来捕获异常对象,因为我们抛出的异常是一个字符串。
如果没有匹配的catch
块来处理异常,异常将继续向上层调用栈传播,直到找到一个匹配的catch
块或者到达程序的入口点(main函数)。如果一直没有找到匹配的catch
块,程序将终止并显示一个未处理异常的错误消息。
标准异常体系
C++标准异常体系定义了一组异常类,用于以统一的方式处理异常情况。这些异常类都派生自基类std::exception
,该基类定义了一些通用的操作和成员函数,如what()
函数用于返回异常的描述信息。
class exception
{
public:
exception() _GLIBCXX_USE_NOEXCEPT { }
virtual ~exception() _GLIBCXX_USE_NOEXCEPT;
/** Returns a C-style character string describing the general cause
* of the current error. */
virtual const char* what() const _GLIBCXX_USE_NOEXCEPT;
};
C++标准异常体系中的异常类包括:
std::bad_alloc
:内存分配失败时 抛出的异常。std::bad_cast
:类型转换失败时 抛出的异常。std::bad_exception
:在处理异常时 抛出的异常。std::bad_typeid
:typeid
操作符获取类型信息失败时 抛出的异常。std::logic_error
:由程序逻辑错误 引起的异常,包括std::invalid_argument
、std::domain_error
、std::length_error
、std::out_of_range
等异常。std::runtime_error
:在运行时发生的异常,包括std::range_error
、std::overflow_error
、std::underflow_error
等异常。
自定义异常
除了以上这些标准异常类,还可以自定义异常类,只需派生自std::exception
即可,需要添加头文件 #include<stdexcept> 。
一个抛出自定义异常的例子:
#include <iostream>
#include <stdexcept>
using namespace std;
class MyException :public exception
{
public:
// 覆盖what函数
// throw():异常规格说明
// 表示此函数不会出现任何异常的抛出
const char* what() const throw()
{
return "自定义类型异常";
}
};
void show(string a,string b)
{
if(a == "#" || b == "#")
{
throw MyException();
}
cout << a << b << endl;
}
int main()
{
cout << "请输入两个字符串" << endl;
string a;
string b;
cin >> a >> b;
try
{
show(a,b);
}
catch(MyException &e)
{
cout << "返回异常信息:" << e.what() << endl;
}
cout << "您输入的是:" << a << b << endl;
return 0;
}
多重捕获
在C++中,可以使用多重异常捕获来处理不同类型的异常。多重异常捕获允许在同一个try
块中捕获多个不同类型的异常,并执行相应的处理操作。
多重异常捕获的语法如下所示:
try {
// 代码块
}
catch (ExceptionType1 ex) {
// 处理类型为ExceptionType1的异常
}
catch (ExceptionType2 ex) {
// 处理类型为ExceptionType2的异常
}
// 可以添加更多的catch块
catch (...) {
// 处理其他类型的异常
}
在try
块中的代码可能会抛出不同类型的异常,每一个catch
块都会尝试捕获指定的异常类型。当发生异常时,C++会按照catch
块的顺序来匹配异常类型,如果找到匹配的catch
块,则执行相应的处理操作。
请注意以下几点:
- 异常类型需要与
catch
块中指定的类型相匹配,包括派生类型(多态)。 catch
块的顺序很重要,应该按照从特定到一般的顺序排列。- 可以添加多个
catch
块来处理不同类型的异常。 - 可以使用省略号
...
来捕获其他未被前面的catch
块捕获的异常,通常在最后一个catch
块中使用。
通过多重异常捕获,可以灵活地处理不同类型的异常,确保程序在遇到异常时能够进行适当的处理操作。
粗略捕获
粗略异常捕获(也称为粗糙的异常处理)是通过catch
块捕获异常,除了可以直接捕获异常类型外,也可以捕获异常的基类,甚至所有异常类型。粗略异常捕获使用省略号...
作为异常类型,可以捕获任何类型的异常。
以下是C++中粗略异常捕获的语法:
try {
// 代码块
}
catch (...) {
// 处理所有类型的异常
}
在try
块中的代码可能会抛出任何类型的异常,当发生异常时,粗略异常捕获的catch
块会捕获并处理异常。您可以在catch
块中执行适当的操作,如输出错误信息、记录日志或进行其他处理。
粗略异常捕获应该在某些情况下使用,例如当您希望在程序遇到任何类型的异常时都能进行某种处理时。然而,粗略异常捕获会损失异常的详细信息,因此在一般情况下,更推荐使用多重异常捕获来处理不同类型的异常,以便根据异常类型采取相应的处理方式。