异常概述
1. 异常处理的重要性和作用: 异常处理是编程中的一个核心组成部分,因为它提供了一种方法来处理程序运行时可能遇到的意外情况,例如文件未找到、网络连接丢失或无效的用户输入等。当这些情况发生时,程序可以优雅地处理它们,而不是崩溃或产生未定义的行为。正确的异常处理可以帮助:
- 保持程序的稳定性
- 提供更友好的用户体验
- 使开发者更容易地调试和诊断问题
- 确保程序的安全性
2. C++中异常处理的基本概念:
Cpp异常处理的三个关键字:try
、catch
、throw
。
- try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块。
- catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。
- throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
标准异常
Cpp 标准库中提供了一组预定义的异常类,它们是从std::exception
类派生出来的,并在<exception>
头文件中定义。这些异常类形成了一个层次结构,以便您可以编写捕获一般异常的处理程序,或更具体地捕获某些特定类型的异常。
以下是C++标准异常类的部分层次结构:
- std::exception
- 基类,可以捕获所有从这个类派生出来的异常。
- 提供了一个虚拟成员函数
what()
,返回一个表示异常原因的C风格字符串。
- std::bad_alloc
- 当
new
运算符不能为新对象分配足够的内存时抛出。
- 当
- std::bad_cast
- 当用
dynamic_cast
进行不合法的类型转换时抛出。
- 当用
- std::logic_error
- 表示程序逻辑错误。
- std::domain_error
- 当函数接收到超出其定义域的参数时抛出。
- std::invalid_argument
- 当提供了无效的参数时抛出。
- std::length_error
- 当试图创建超过最大大小的
std::string
时抛出。
- 当试图创建超过最大大小的
- std::out_of_range
- 例如,当使用
std::vector::at()
访问超出范围的元素时抛出。
- 例如,当使用
- std::runtime_error
- 表示在运行时检测到的错误。
- std::overflow_error
- 当发生算术上溢时抛出。
- std::underflow_error
- 当发生算术下溢时抛出。
- std::range_error
- 当算术操作的结果不适用于其定义域时抛出。
try / catch 语句
在C++中,try/catch
语句为程序提供了一个捕获和处理运行时异常的机制,使得程序在遭遇预期外的错误时不会崩溃,而是能够进行优雅的异常处理。这种结构允许代码在可能抛出异常的try
块中执行,并使用一个或多个catch
块来捕获和处理这些异常。
语法示例:
try {
// 代码,可能会抛出异常
}
catch (ExceptionType1 e1) {
// 处理ExceptionType1类型的异常
}
catch (ExceptionType2 e2) {
// 处理ExceptionType2类型的异常
}
...
catch (...) {
// 捕获所有其他类型的异常
}
#include <iostream>
#include <stdexcept> // 需要这个头文件来使用内置的异常类型
int main() {
try {
// 尝试执行可能会抛出异常的代码
int dividend = 10;
int divisor = 0;
if (divisor == 0) {
throw std::runtime_error("除数不能为零!"); // 使用throw关键字抛出一个异常
}
int result = dividend / divisor;
std::cout << "结果是:" << result << std::endl;
} catch (const std::runtime_error &e) {
// 捕获并处理异常
std::cout << "发生了一个错误:" << e.what() << std::endl; // e.what()返回异常的描述信息
}
return 0;
}
在这个例子中,当发现除数为0时,我们使用throw
抛出一个std::runtime_error
异常。eatch
块会捕获这个异常并处理它,使程序不会崩溃,并给用户提供一个有意义的错误消息。
自定义异常
自定义异常的操作步骤:
- 创建异常类
- 自定义异常通常通过继承标准的
exception
类来创建。 - 覆盖
what()
方法,返回描述异常的字符串。
- 自定义异常通常通过继承标准的
- 抛出自定义异常:
- 使用
throw
关键字,如同使用内置异常一样。
- 使用
- 捕获自定义异常:
- 使用
try/catch
块捕获自定义异常,与捕获内置异常相同。
- 使用
示例:
#include <iostream>
#include <exception>
// 1. 创建自定义异常类
class DivideByZeroException : public std::exception {
public:
const char* what() const throw() {
return "Attempted to divide by zero!";
}
};
double divide(double a, double b) {
if (b == 0.0) {
throw DivideByZeroException(); // 2. 抛出自定义异常
}
return a / b;
}
int main() {
try {
std::cout << divide(10.0, 0.0) << std::endl;
}
catch (const DivideByZeroException& e) { // 3. 捕获自定义异常
std::cout << "Error: " << e.what() << std::endl;
}
return 0;
}