1、什么是异常?
在计算机程序中,异常是指程序执行过程中发生的错误或异常情况。这些异常可能是由于无效的输入、资源不可用、逻辑错误等原因引起的。通过使用异常处理机制,程序可以在出现异常时采取相应的措施,如错误处理、资源释放、日志记录等。
2、异常处理的基本原则
异常处理遵循以下基本原则:
2.1抛出异常(Throwing Exceptions):
当出现错误或异常情况时,可以使用 throw 关键字抛出异常。抛出的异常可以是内置类型(如整数、字符等)或自定义类型。
throw MyException("Something went wrong");
2.2 捕获异常(Catching Exceptions):
使用 try-catch 块来捕获和处理异常。try 块用于包裹可能引发异常的代码块,而 catch 块用于捕获并处理特定类型的异常。
try {
// 可能引发异常的代码块
} catch (ExceptionType ex) {
// 处理 ExceptionType 类型的异常
}
2.3 处理异常(Handling Exceptions):
在 catch 块中,可以对捕获的异常进行处理。处理异常的方式可以是输出错误信息、进行日志记录、恢复程序状态等。也可以选择重新抛出异常或抛出其他异常。
try {
// 可能引发异常的代码块
} catch (ExceptionType1 ex1) {
// 处理 ExceptionType1 类型的异常
} catch (ExceptionType2 ex2) {
// 处理 ExceptionType2 类型的异常
} catch (...) {
// 处理其他类型的异常
}
2.4 栈展开(Stack Unwinding):
当发生异常时,程序会在调用栈中寻找匹配的 catch 块来处理异常。如果没有找到匹配的 catch 块,异常会被传递给上层调用栈中的调用者,直到找到匹配的 catch 块为止。如果最终没有找到任何匹配的 catch 块,程序将终止,并显示未捕获的异常信息。
2.5 异常安全(Exception Safety):
在编写代码时,需要考虑异常安全性。这意味着在出现异常时,程序应保持稳定状态,并确保资源的正确释放,以避免资源泄漏和数据损坏
实例:
#include <iostream>
#include <stdexcept>
double calculateAverage(const double *numbers, int size) {
if (numbers == nullptr || size <= 0) {
throw std::invalid_argument("Invalid input");
}
double sum = 0;
for (int i = 0; i < size; i++) {
sum += numbers[i];
}
return sum / size;
}
void processArray(const double *numbers, int size) {
try {
double average = calculateAverage(numbers, size);
std::cout << "Average: " << average << std::endl;
} catch (std::exception &ex) {
std::cout << "Exception occurred in calculateAverage(): " << ex.what() << std::endl;
// 执行错误处理逻辑,如输出错误信息、恢复程序状态等
throw; // 重新抛出异常
}
}
void processData(const double *numbers, int size) {
try {
processArray(numbers, size);
} catch (std::exception &ex) {
std::cout << "Exception occurred in processArray(): " << ex.what() << std::endl;
// 执行错误处理逻辑,如输出错误信息、恢复程序状态等
throw; // 重新抛出异常
}
}
int main() {
double numbers[] = {1.0, 2.0, 3.0, 4.0, 5.0};
try {
processData(numbers, 5);
} catch (std::exception &ex) {
std::cout << "Exception occurred in processData(): " << ex.what() << std::endl;
// 执行错误处理逻辑,如输出错误信息、恢复程序状态等
}
return 0;
}
自定义异常类:
在 C++ 中,你可以自定义异常类来表示特定的异常情况。自定义异常类通常继承自标准库中的 std::exception 类,并实现 what() 函数来提供异常的描述信息。
下面是一个自定义异常类的示例:
#include <exception>
class MyException : public std::exception {
public:
MyException(const char* message) : m_message(message) {}
const char* what() const noexcept override {
return m_message;
}
private:
const char* m_message;
};
通过自定义异常类,你可以根据程序的需求定义不同类型的异常,并在异常处理器中针对不同类型的异常做出相应的处理。
异常规范(Exception Specifications)
异常规范用于指定函数可能抛出的异常类型。它可以在函数声明中使用 throw 关键字来指定特定的异常类型。然而,C++11 引入了更推荐的异常规范方式,即使用 noexcept 关键字来指示函数不会抛出异常。
void myFunction() noexcept {
// 不会抛出异常的函数体
}
异常处理的最佳实践
以下是一些在使用异常处理时的最佳实践:
只捕获你知道如何处理的异常:在 catch 块中,只捕获你能够处理的异常类型。不要捕获所有异常类型,以免掩盖潜在的错误。
确保资源的正确释放:在捕获和处理异常时,确保释放已分配的资源,以避免资源泄漏。
避免在构造函数和析构函数中抛出异常:在构造函数和析构函数中抛出异常可能导致不可预料的行为,因此尽量避免在这些函数中抛出异常。
清晰地记录和报告异常:在处理异常时,清晰地记录和报告异常信息,以便进行故障排查和调试。