C++ 异常处理:Try、Catch、Throw 示例

什么是 C++ 异常处理?

C++ 中的异常处理为您提供了一种处理意外情况(如运行时错误)的方法。因此,当发生意外情况时,程序控制将被转移到称为处理程序的特殊函数。

为了捕获异常,您会将某些代码段置于异常检查之下。该代码段位于 try-catch 块内。

如果在该代码段中发生异常情况,将抛出异常。接下来,异常处理程序将接管程序的控制权。

如果没有发生异常情况,代码将正常执行。处理程序将被忽略。

在本 C++ 教程中,您将学习

为什么需要异常处理?

以下是使用 C++ 异常处理的原因:

  • 您将把错误处理代码与正常代码分开。代码将更具可读性,更易于维护。
  • 函数可以处理它们选择的异常。即使函数抛出许多异常,它也只会处理其中一些。调用者将处理未捕获的异常。

异常处理关键字

C++ 中的异常处理围绕这三个关键字展开:

  • throw – 当程序遇到问题时,它会抛出异常。throw 关键字帮助程序执行抛出操作。
  • catch – 程序使用异常处理程序来捕获异常。它被添加到程序中需要处理问题的部分。这是使用 catch 关键字完成的。
  • try – try 块标识将激活某些异常的代码块。它应该后面跟着一个或多个 catch 块。

假设一个代码块将引发异常。异常将被方法使用 try 和 catch 关键字捕获。try/catch 块应包含可能引发异常的代码。此类代码称为受保护代码。

语法

try/catch 的语法如下:

try {
   // the protected code
} catch( Exception_Name exception1 ) {
   // catch block
} catch( Exception_Name exception2 ) {
   // catch block
} catch( Exception_Name exceptionN ) {
   // catch block
}
  • 尽管我们有一个 try 语句,但我们可以有许多 catch 语句。
  • ExceptionName 是要捕获的异常的名称。
  • exception1、exception2 和 exceptionN 是您为引用异常定义的名称。

示例 1

#include<iostream>
#include<vector>
using namespace std;

int main() {
	vector<int> vec;
	vec.push_back(0);	
	vec.push_back(1);	
	// access the third element, which doesn't exist
	try
	{
		vec.at(2);		
	}
	catch (exception& ex)
	{
		cout << "Exception occurred!" << endl;
	}
	return 0;
}

输出

Exception Handling Keywords

这是代码的屏幕截图:

Exception Handling Keywords

代码解释

  1. 在程序中包含 iostream 头文件以使用其函数
  2. 在程序中包含 vector 头文件以使用其函数。
  3. 在程序中包含 std 命名空间,以便在不调用它的情况下使用其类。
  4. 调用 main() 函数。程序逻辑应添加到其主体中。
  5. 创建一个名为 vec 的向量来存储整数数据。
  6. 向名为 vec 的向量添加元素 0。
  7. 向名为 vec 的向量添加元素 1。
  8. 注释。它将被C++ 编译器忽略。
  9. 使用 try 语句捕获异常。{ 标记 try/catch 块的开头。添加到该块中的代码将成为受保护代码。
  10. 尝试访问向量 vec 中索引为 2(第三个元素)的元素。此元素不存在。
  11. try/catch 块的结尾。
  12. 捕获异常。返回的错误消息将存储在变量 ex 中。
  13. 如果捕获到异常,则在控制台上打印一条消息。
  14. catch 块的结尾。
  15. 程序应在成功执行后返回值。
  16. main() 函数主体的结尾。

示例 2

#include <iostream>
using namespace std;
double zeroDivision(int x, int y) {

	if (y == 0) {
		throw "Division by Zero!";
	}
	return (x / y);
}

int main() {
	int a = 11;
	int b = 0;
	double c = 0;

	try {
		c = zeroDivision(a, b);
		cout << c << endl;
	}
	catch (const char* message) {
		cerr << message << endl;
	}
	return 0;
}

输出

Exception Handling Keywords

这是代码的屏幕截图:

Exception Handling Keywords

代码解释

  1. 在程序中包含 iostream 头文件以使用其函数。
  2. 在程序中包含 std 命名空间,以便在不调用它的情况下使用其类。
  3. 创建一个名为 zeroDivision 的函数,该函数接受两个整数参数 x 和 y。该函数应返回 double 类型的结果。
  4. 使用 if 语句检查变量参数 y 的值是否为 0。{ 标记 if 主体的开头。
  5. 如果 y 为 0,则返回/抛出的消息。
  6. if 语句主体的结束。
  7. zeroDivision 函数应返回 x/y 的值。
  8. zeroDivision 函数的结尾。
  9. 调用 main() 方法。{ 标记此方法的开头。
  10. 声明一个整数变量并为其赋值 11。
  11. 声明一个整数变量 b 并为其赋值 0。
  12. 声明一个 double 变量 c 并为其赋值 0。
  13. 使用 try 语句捕获异常。{ 标记 try/catch 块的开头。添加到该块中的代码将成为受保护代码。
  14. 调用 zeroDivision 函数,并将参数 a 和 b,即 11 和 0,传递给它。此操作的结果将存储在变量 c 中。
  15. 在控制台上打印变量 c 的值。
  16. try/catch 块的结尾。
  17. 捕获异常。返回的错误消息将存储在变量 message 中。
  18. 在控制台上打印返回的错误消息。
  19. catch 块的结尾。
  20. 程序应在成功执行后返回值。
  21. main() 函数主体的结尾。

C++ 标准异常

C++ Standard Exceptions

C++ 随附一个在 <exception> 类中定义的标准异常列表。这些如下所述:

Exception 描述
std::exception 这是一个异常,也是所有标准 C++ 异常的父类。
std::bad_alloc 此异常由 new 关键字抛出。
std::bad_cast 这是由 dynamic_cast 抛出的异常。
std::bad_exception C++ 程序中处理意外异常的有用设备。
std::bad_typeid 由 typeid 抛出的异常。
std::logic_error 理论上可以通过阅读代码检测到此异常。
std::domain_error 这是在使用数学上无效的域后抛出的异常。
std::invalid_argument 用于无效参数时抛出的异常。
std::length_error 创建过大的 std::string 后抛出的异常。
std::out_of_range 由 at() 方法抛出。
std::runtime_error 这是无法通过阅读代码检测到的异常。
std::overflow_error 在发生数学溢出后抛出的此异常。
std::range_error 尝试存储超出范围的值时抛出的此异常。
std::underflow_error 发生数学下溢后抛出的异常。

用户定义异常

C++ std::exception 类允许我们定义可以作为异常抛出的对象。此类已在 <exception> 头文件中定义。该类为我们提供了一个名为 what 的虚拟成员函数。

此函数返回 char * 类型的空终止字符序列。我们可以在派生类中覆盖它以具有异常描述。

示例

#include <iostream>
#include <exception>
using namespace std;

class newException : public exception
{
	virtual const char* what() const throw()
	{
		return "newException occurred";
	}
} newex;

int main() {

	try {
		throw newex;
		}
	catch (exception& ex) {
		cout << ex.what() << '\n';
	}
	return 0;	
}

输出

User-Defined Exceptions

这是代码的屏幕截图:

User-Defined Exceptions

代码解释

  1. 在我们的程序中包含 iostream 头文件。我们将使用其函数而不会出错。
  2. 在我们的程序中包含 exception 头文件。我们将使用其 like what 等函数而不会出错。
  3. 在程序中包含 std 命名空间,以便在使用其类时无需调用它。
  4. 创建一个名为 newException 的新类。此类继承 C++ 的 exception 类。
  5. 类主体的开头。
  6. 重写 exception 头文件中定义的虚拟成员函数 what()。然后我们将描述我们自己的异常,即 new exception。
  7. 开始 new exception 的定义。
  8. 捕获 new exception 时要返回的消息。
  9. new exception 主体的结尾。
  10. newException 类的结尾。newex 是捕获我们新异常后将使用的名称,然后将调用 newException。
  11. 调用 main() 函数。程序逻辑应添加到其主体中。{ 标记其主体的开头。
  12. 使用 try 语句标记我们需要标记异常的代码。{ 标记 try/catch 块的开头。被此包围的代码将成为受保护代码。
  13. 如果捕获到 newex 异常,则抛出它。
  14. try 主体的结尾。
  15. 使用 catch 语句捕获异常。异常错误消息将存储在变量 ex 中。
  16. 在控制台上打印异常错误消息。
  17. catch 语句主体的结尾。
  18. 如果程序成功执行,则应返回值。
  19. main() 函数体结束。

摘要

  • 通过 C++ 的异常处理,您可以处理运行时错误。
  • 运行时错误是在程序执行期间发生的错误。
  • 异常处理可帮助您处理程序中的任何意外情况。
  • 当意外情况发生时,程序控制被转移到处理程序。
  • 要捕获异常,您需要将一段代码放置在 try-catch 块下。
  • throw 关键字帮助程序抛出异常,从而帮助程序处理问题。
  • try 关键字有助于识别将激活某些异常的代码块。
  • 我们可以重写 exception 头文件的 what() 函数来定义我们的异常。