✨博客主页 | ||
---|---|---|
何曾参静谧的博客 | ||
📌文章专栏 | ||
「C/C++」C/C++程序设计 | ||
📚全部专栏 | ||
「VS」Visual Studio | 「C/C++」C/C++程序设计 | 「UG/NX」BlockUI集合 |
「Win」Windows程序设计 | 「DSA」数据结构与算法 | 「UG/NX」NX二次开发 |
「QT」QT5程序设计 | 「File」数据文件格式 | 「PK」Parasolid函数说明 |
「Math」探秘数学世界 |
目录
- C++异常处理详解
- 一、C++ 异常处理的基本结构
- 二、自定义异常类
- 三、异常规范(C++11 已废弃)
- 四、标准异常类
- 五、多重捕获和重新抛出
- 六、总结
C++异常处理详解
在现代编程中,异常处理是确保程序健壮性和可靠性的重要机制之一。C++ 提供了一套强大且灵活的异常处理框架,允许程序在运行时遇到错误或异常情况时,能够优雅地处理这些状况,而不是简单地崩溃或终止。本文将深入探讨 C++ 中的异常处理机制,包括 try
、throw
和 catch
关键字的使用,以及自定义异常类、异常规范、标准异常类和多重捕获等内容。
一、C++ 异常处理的基本结构
C++ 的异常处理主要依赖于三个关键字:try
、throw
和 catch
。
-
try 块:
try
块标记了一段可能抛出异常的代码。在try
块内部,你可以写正常的程序代码,同时也可以调用可能抛出异常的函数或方法。try { // 可能抛出异常的代码 }
-
throw 语句:
当try
块中的代码检测到某个错误或异常情况时,可以使用throw
语句抛出一个异常。throw
后面可以跟基本数据类型(如int
、char
等)、对象或者是指针。throw expression;
例如,如果检测到数组越界,可以抛出一个整数异常:
throw 100; // 抛出一个整数异常
-
catch 块:
catch
块用于捕获和处理由try
块中抛出的异常。每个catch
块都会指定一个异常类型,当抛出的异常类型与catch
块指定的类型匹配时,该catch
块就会被执行。catch (exception_type variable) { // 处理异常的代码 }
例如,捕获并处理前面抛出的整数异常:
try { throw 100; } catch (int e) { std::cout << "Caught an integer exception: " << e << std::endl; }
二、自定义异常类
在实际开发中,常常需要抛出和捕获具有特定意义的异常。为此,可以定义自己的异常类。自定义异常类通常继承自 std::exception
类(或其派生类),这样可以利用标准异常类提供的功能,如获取错误消息等。
#include <iostream>
#include <exception>
#include <string>
class MyException : public std::exception {
public:
MyException(const std::string& message) : msg_(message) {}
virtual const char* what() const noexcept override {
return msg_.c_str();
}
private:
std::string msg_;
};
int main() {
try {
throw MyException("Something went wrong!");
} catch (const MyException& e) {
std::cerr << "Caught MyException: " << e.what() << std::endl;
}
return 0;
}
三、异常规范(C++11 已废弃)
在 C++11 之前,函数声明中可以包含异常规范,指明该函数可能抛出的异常类型。不过,由于该特性在实际应用中很少使用且存在限制,C++11 标准已将其废弃,并在 C++17 中完全移除。因此,这里仅做简要介绍,不建议在新代码中使用。
void mightThrowException() throw(int, std::bad_alloc); // C++98/03 语法,C++11 已废弃
四、标准异常类
C++ 标准库提供了一系列标准异常类,这些类继承自 std::exception
类。使用标准异常类可以让代码更加规范,便于理解和维护。
std::bad_alloc
:内存分配失败时抛出。std::bad_cast
:动态类型转换失败时抛出(如dynamic_cast
失败)。std::bad_exception
:未知的异常被std::unexpected
函数抛出时抛出。std::domain_error
:数学函数域错误时抛出(如sqrt(-1)
)。std::invalid_argument
:传递给函数的参数无效时抛出。std::length_error
:试图创建超过允许长度的对象时抛出(如std::string
太长)。std::out_of_range
:使用超出有效范围的值时抛出(如数组索引越界)。std::overflow_error
:算术运算结果超出可表示范围时抛出(如整数溢出)。std::range_error
:使用无效范围的值时抛出(如std::stoi
转换失败)。std::runtime_error
:运行时错误时抛出(一般异常)。std::underflow_error
:算术运算结果低于可表示范围时抛出(如负整数下溢)。
五、多重捕获和重新抛出
一个 try
块可以对应多个 catch
块,以捕获不同类型的异常。此外,还可以在 catch
块中重新抛出异常,以便上层调用者处理。
try {
// 可能抛出多种异常的代码
} catch (const std::runtime_error& e) {
std::cerr << "Runtime error: " << e.what() << std::endl;
} catch (const std::bad_alloc& e) {
std::cerr << "Memory allocation failed: " << e.what() << std::endl;
} catch (...) {
std::cerr << "Unknown exception caught!" << std::endl;
// 可以选择重新抛出异常
throw;
}
在上面的代码中,catch (...)
是一个通配符捕获块,它可以捕获所有类型的异常。
六、总结
C++ 的异常处理机制为编写健壮和可靠的程序提供了强大的支持。通过合理使用 try
、throw
和 catch
关键字,以及自定义异常类和标准异常类,可以显著提升代码的错误处理能力和可维护性。在实际开发中,应根据具体需求选择合适的异常处理方式,并尽量避免滥用异常,以保持代码的清晰和高效。