「C++系列」异常处理
【人工智能教程】,前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。
点击跳转到网站:【人工智能教程】
文章目录
- 一、异常处理
- 1. 基本概念
- 2. 示例代码
- 3. 注意事项
- 二、常见的异常类
- 1. 继承自`std::exception`的基类
- 2. 逻辑错误(`std::logic_error`派生)
- 3. 运行时错误(`std::runtime_error`派生)
- 4. 特定于内存和类型转换的异常
- 5. 自定义异常类
- 6. 使用异常类的示例
- 三、相关链接
一、异常处理
C++ 异常处理是一种错误处理机制,它允许程序在运行时检测和处理错误情况。这种机制通过使用 try
、catch
和 throw
关键字来实现。当函数遇到无法处理的错误时,它会抛出一个异常(通过 throw
关键字),这个异常可以被调用者捕获并处理(通过 catch
块)。如果没有被捕获,异常会传播到更高层的调用者,直到被捕获或导致程序终止。
1. 基本概念
- throw:用于抛出一个异常。它可以抛出 C++ 中的任何类型,但通常是抛出一个从标准异常类派生的对象。
- try:用于指定代码块,当块内发生异常时,程序的控制流会跳转到与之关联的
catch
块。 - catch:用于捕获并处理异常。
catch
块可以紧跟在try
块之后,并且可以有多个catch
块来捕获不同类型的异常。
2. 示例代码
#include <iostream>
#include <stdexcept> // 包含标准异常类
void func() {
// 假设这里发生了一个错误
throw std::runtime_error("发生了一个运行时错误!");
}
int main() {
try {
func(); // 调用func,它可能会抛出一个异常
} catch (const std::runtime_error& e) {
// 捕获到runtime_error异常
std::cerr << "捕获到异常: " << e.what() << std::endl;
} catch (...) {
// 捕获所有其他类型的异常
std::cerr << "捕获到未知异常" << std::endl;
}
return 0;
}
3. 注意事项
- 异常规格:在 C++11 之前,函数可以声明它可以抛出的异常类型(异常规格)。但从 C++11 开始,非抛出异常规格(
throw()
)被废弃,并且在 C++17 中被完全移除。现代 C++ 代码通常不再使用异常规格。 - 资源泄露:在使用异常处理时,要特别注意资源管理,防止资源泄露。一种常见的方法是使用 RAII(Resource Acquisition Is Initialization)技术,通过智能指针(如
std::unique_ptr
和std::shared_ptr
)来自动管理资源。 - 异常层次结构:在设计自定义异常时,应该继承自标准异常类(如
std::exception
),这有助于维护清晰的异常层次结构,并允许调用者更容易地处理异常。 - 避免在析构函数中抛出异常:在析构函数中抛出异常可能会导致程序崩溃,因为析构函数是在处理异常的过程中被调用的。如果析构函数需要处理错误情况,它应该采用其他错误处理机制(如记录错误日志或设置错误状态码)。
- 性能考虑:虽然异常处理提供了强大的错误处理机制,但它可能会对性能产生负面影响。因此,在性能敏感的代码区域中,应该谨慎使用异常处理,并考虑使用其他错误处理机制(如错误码和错误状态)。
二、常见的异常类
C++中常见的异常类主要包括标准异常类和自定义异常类。标准异常类是由C++标准库提供的,用于表示各种常见的错误情况。以下是一些常见的标准异常类:
1. 继承自std::exception
的基类
std::exception
:所有标准异常的基类,提供了基本的异常接口,包括what()
函数,该函数返回一个表示异常的字符串指针。
2. 逻辑错误(std::logic_error
派生)
逻辑错误是在程序运行前可以检测出来的错误,它们通常是由于程序内部的逻辑问题导致的。
std::domain_error
:当函数的参数值不在其允许的有效范围内时抛出。std::invalid_argument
:指出函数的一个无效参数。std::length_error
:当尝试生成一个超出该类型最大长度的对象时抛出。std::out_of_range
:当使用一个超出有效范围的值时抛出,如在数组或字符串中采用了一个错误的索引。
3. 运行时错误(std::runtime_error
派生)
运行时错误是在程序运行过程中才能检测到的错误。
std::range_error
:当内部计算时发生区间错误时抛出。std::overflow_error
:当算术运算结果超出可表示的最大值时抛出。std::underflow_error
:当算术运算结果超出可表示的最小值时抛出。
4. 特定于内存和类型转换的异常
std::bad_alloc
:当new
操作无法分配足够的内存时抛出。std::bad_cast
:在运行时类型识别中有一个无效的dynamic_cast
表达式时抛出。std::bad_typeid
:当对空指针使用typeid
操作时抛出。
5. 自定义异常类
除了上述标准异常类外,程序员还可以根据需要创建自定义异常类。自定义异常类通常通过继承自std::exception
或某个更具体的标准异常类来实现,以便提供额外的错误信息或特定的行为。
6. 使用异常类的示例
#include <iostream>
#include <stdexcept>
int main() {
try {
// 假设这里有一段可能抛出异常的代码
if (/* 某种错误条件 */) {
throw std::invalid_argument("无效的参数");
}
} catch (const std::invalid_argument& e) {
std::cerr << "捕获到异常: " << e.what() << std::endl;
} catch (...) {
std::cerr << "捕获到未知异常" << std::endl;
}
return 0;
}
在编写C++程序时,合理使用异常处理机制可以提高程序的健壮性和可维护性。通过抛出和捕获异常,程序可以在遇到错误时优雅地处理,而不是突然崩溃或产生未定义的行为。
三、相关链接
- Visual Studio Code下载地址
- Sublime Text下载地址
- 「C++系列」C++简介、应用领域
- 「C++系列」C++ 基本语法
- 「C++系列」C++ 数据类型
- 「C++系列」C++ 变量类型
- 「C++系列」C++ 变量作用域
- 「C++系列」C++ 常量知识点-细致讲解
- 「C++系列」C++ 修饰符类型
- 「C++系列」一篇文章说透【存储类】
- 「C++系列」一篇文章讲透【运算符】
- 「C++系列」循环
- 「C++系列」判断
- 「C++系列」函数/内置函数
- 「C++系列」数字/随机数
- 「C++系列」数组
- 「C++系列」字符串
- 「C++系列」指针
- 「C++系列」引用
- 「C++系列」日期/时间
- 「C++系列」输入/输出
- 「C++系列」数据结构
- 「C++系列」vector 容器
- 「C++系列」类/对象
- 「C++系列」继承
- 「C++系列」重载运算符/重载函数
- 「C++系列」多态
- 「C++系列」数据抽象
- 「C++系列」数据封装
- 「C++系列」 接口(抽象类)
- 「C++系列」文件和流