深入探究C++的stdexcept
类库
引言
在C++编程中,异常处理是一个不可或缺的部分。C++标准库提供了一组用于异常处理的标准类,这些类都定义在头文件中。本文将深入探讨这些异常类,以及它们如何与C++的异常处理机制相结合。
“C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off.” — Bjarne Stroustrup, 《The C++ Programming Language》
C++语言本身或者标准库抛出的异常都是exception的子类,称为标准异常。捕获所有的标准异常的语句.
概览
在C++中,头文件定义了一系列用于标准异常处理的类。这些类都继承自
std::exception
基类。
类名 | 描述 | 常用场景 |
std::exception |
基础异常类 | 作为其他异常类的基类 |
std::logic_error |
逻辑错误 | 程序逻辑错误 |
std::runtime_error |
运行时错误 | 程序运行时出现的错误 |
std::invalid_argument |
无效参数 | 函数参数无效 |
std::out_of_range |
越界 | 访问数组、向量等越界 |
std::exception
try{ //可能抛出异常的语句 }catch(exception &e) //使用引用是为了提高效率,不然需要经过一次对象拷贝过程。 { //处理异常的语句 }
std::exception
是所有标准异常类的基类。它提供了一个名为what()
的成员函数,用于返回一个C风格的字符串,描述异常的详情。
#include <iostream> #include <stdexcept> int main() { try { throw std::exception("An exception occurred"); } catch (const std::exception& e) { std::cout << e.what() << std::endl; // Output: An exception occurred } return 0; }
在这个例子中,我们使用throw
关键字抛出一个std::exception
对象,并在catch
块中捕获它。
– exception 类的直接派生类
异常名称 | 说 明 |
logic_error | 程序逻辑问题. |
runtime_error | 只有在运行时才能检测出的问题. |
bad_alloc | 使用 new 或 new[ ] 分配内存失败时抛出的异常。 |
bad_typeid | 使用 typeid 操作一个 NULL 指针,而且该指针是带有虚函数的类,这时抛出 bad_typeid 异常。 |
bad_cast | 使用 dynamic_cast 转换失败时抛出的异常。 |
ios_base::failure | io 过程中出现的异常。 |
bad_exception | 这是个特殊的异常,如果函数的异常列表里声明了 bad_exception 异常,当函数内部抛出了异常列表中没有的异常时,如果调用的 unexpected() 函数中抛出了异常,不论什么类型,都会被替换为 bad_exception 类型。 |
std::logic_error 与 std::runtime_error
这两个类是std::exception
的直接子类,用于处理逻辑错误和运行时错误。
#include <stdexcept> void foo(int x) { if (x < 0) { throw std::logic_error("Negative value"); } if (x > 100) { throw std::runtime_error("Value too large"); } }
在这个例子中,foo
函数接受一个整数x
作为参数。如果x
是负数,函数会抛出一个std::logic_error
异常。如果x
大于100,函数会抛出一个std::runtime_error
异常。
- logic_error 的派生类(逻辑错误)
异常名称 | 说 明 |
length_error | 试图生成一个超出该类型最大长度的对象时抛出该异常,例如 vector 的 resize 操作。 |
domain_error | 参数的值域错误,主要用在数学函数中,例如使用一个负值调用只能操作非负数的函数。 |
out_of_range | 超出有效范围。 |
invalid_argument | 参数不合适。在标准库中,当利用string对象构造 bitset 时,而 string 中的字符不是 0 或1 的时候,抛出该异常。 |
- runtime_error 的派生类(运行时错误)
异常名称 | 说 明 |
range_error | 计算结果超出了有意义的值域范围。 |
overflow_error | 算术计算上溢。 |
underflow_error | 算术计算下溢。 |
std::invalid_argument 与 std::out_of_range
这两个类是std::logic_error
的子类,用于更具体的异常场景。
#include <vector> #include <stdexcept> void bar(std::vector<int>& vec, int index) { if (index < 0) { throw std::invalid_argument("Negative index"); } if (index >= vec.size()) { throw std::out_of_range("Index out of range"); } }
在这个例子中,bar
函数接受一个std::vector
和一个索引index
。如果索引是负数,函数会抛出一个std::invalid_argument
异常。如果索引超出向量的大小,函数会抛出一个std::out_of_range
异常。
源码解析
在GCC编译器中,的实现可以在
/usr/include/c++/版本号/bits/stdexcept.h
中找到。这些异常类大多数都是简单的类,主要是通过继承std::exception
并实现what()
函数来提供异常信息。
总结
异常处理是编程中非常重要的一环,而C++通过提供了一套完善的标准异常类,使得异常处理变得更加方便和规范。这不仅提高了代码的健壮性,也使得程序更容易维护。
“We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.” — Donald Knuth
通过深入了解这些异常类,我们可以更好地理解程序中可能出现的各种问题,并采取相应的措施。这不仅是对代码的一种保护,也是对程序员思维严谨性的一种体现。
希望本文能帮助你更深入地了解C++的异常处理机制。
结语
在我们的编程学习之旅中,理解是我们迈向更高层次的重要一步。然而,掌握新技能、新理念,始终需要时间和坚持。从心理学的角度看,学习往往伴随着不断的试错和调整,这就像是我们的大脑在逐渐优化其解决问题的“算法”。
这就是为什么当我们遇到错误,我们应该将其视为学习和进步的机会,而不仅仅是困扰。通过理解和解决这些问题,我们不仅可以修复当前的代码,更可以提升我们的编程能力,防止在未来的项目中犯相同的错误。
我鼓励大家积极参与进来,不断提升自己的编程技术。无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力。