C++ 异常处理深入探讨,一文打通任督二脉!
对上面代码的分析,可以看到,发生异常时抛出一个对象而不是一个简单的数据类型,可以传递更多的错误信息,但是这样的话,需要针对不同的异常情况定义不同的类。有没有统一的解决方法?C++ 标准库提供了根基类,定义了虚函数what()返回错误描述:展开代码语言:C++自动换行AI代码解释主要就是定义了一个what的虚函数,返回C_style的字符串,主要作用就是描述发生一场的原因。在使用的时候,往往需要自定
、基本语法
C++ 异常处理核心由三个关键字组成:try、throw、catch。

一个简单的示例:
展开
代码语言:C++
自动换行
AI代码解释
#include <stdexcept> #include <limits> #include <iostream> using namespace std; void MyFunc(int c) { if (c > numeric_limits<char>::max()) throw invalid_argument("Argument too large"); // ... } int main() { try { MyFunc(256); // 触发异常 } catch (const invalid_argument& e) { cerr << "Caught: " << e.what() << endl; return -1; } // ... return 0; }
-
throw:抛出异常对象,可是内置类型(
int、double)或自定义类型。 -
catch:按类型匹配并捕获异常,推荐“按
const&捕获”。 -
若找不到匹配的
catch,程序调用std::terminate()并终止。
try在块中,如果引发异常,则它将被其类型与异常匹配的第一个关联catch块捕获。 换言之,执行从 throw 语句跳转到 catch 语句。 如果未找到可用的 catch 块, std::terminate 则将调用并退出程序。 在 c + + 中,可能会引发任何类型,但是,建议引发直接或间接从 std::exception 派生的类型。 在上面的示例中,异常类型 invalid_argument 在标头文件的标准库<stdexcept>中定义。
语法比较简单:throw(抛出)一个数据,然后再用catch(捕获)接收。throw的数据类型可以是任意的,所以当然也可以是一个对象
示例:抛出并捕获自定义对象
展开
代码语言:C++
自动换行
AI代码解释
struct Test { const char* msg; int code; double val; Test(const char* s, int i, double d): msg(s), code(i), val(d) {} void print() const { printf("%s %d %.2f\n", msg, code, val); } }; int main() { try { throw Test("LLF", 520, 13.14); } catch (const Test& e) { e.print(); } }
二、异常处理的基本指导原则
强大的错误处理对于任何编程语言都很有挑战性。 尽管异常提供了多个支持良好错误处理的功能,但它们无法完成所有工作。 若要实现异常机制的优点,请在设计代码时记住异常。
-
断言与异常并用
-
断言(
assert)用于“绝不应发生”的逻辑错误。 -
异常用于“可能发生”的运行时错误(如传参检验、I/O 失败)。
-
-
错误检测与处理应解耦
-
当处理错误的代码与通过一个或多个干预函数调用检测到错误的代码分离时,使用异常;
-
当处理错误的代码与检测到错误的代码紧密耦合时,考虑是否使用错误代码而不是在性能关键循环中。
-
-
对于可能引发或传播异常的每个函数,请提供以下三种异常保证之一:
-
No-throw(失败保证):函数决不抛出异常,常用
noexcept标注。 -
强保证:要么成功,要么状态回滚。
-
基本保证:抛出后对象处于可析构状态,没有资源泄漏。参见 如何设计异常安全性。
-
-
抛出按值,捕获按引用; 不要捕获无法处理的内容。
throw MyException("oops"); // 按值 catch (const MyException& e) { // 按 const& ... }
-
避免使用已弃用的动态异常规范。C++11 起,推荐使用
noexcept,抛出声明(throw(Type))已弃用。 -
不要在析构函数中抛出异常。析构时异常会导致
std::terminate(),可使用noexcept(true)明确标记(不允许对析构函数或内存释放函数进行转义)。 -
应用时使用标准库异常类型。 从 exception 类层次结构派生自定义异常类型。
三、exception 与自定义异常
对上面代码的分析,可以看到,发生异常时抛出一个对象而不是一个简单的数据类型,可以传递更多的错误信息,但是这样的话,需要针对不同的异常情况定义不同的类。有没有统一的解决方法?
C++ 标准库提供了根基类 std::exception,定义了虚函数 what() 返回错误描述:
展开
代码语言:C++
自动换行
AI代码解释
/** * @brief Base class for all library exceptions. * * This is the base class for all exceptions thrown by the standard * library, and by certain language expressions. You are free to derive * your own %exception classes, or use a different hierarchy, or to * throw non-class data (e.g., fundamental types). */ class exception { public: exception() noexcept { } virtual ~exception() noexcept; exception(const exception&) = default; exception& operator=(const exception&) = default; exception(exception&&) = default; exception& operator=(exception&&) = default; /** Returns a C-style character string describing the general cause * of the current error. */ virtual const char* what() const noexcept; };
主要就是定义了一个what的虚函数,返回C_style的字符串,主要作用就是描述发生一场的原因。在使用的时候,往往需要自定义一个异常类,从 std::exception 继承,为你的场景提供更具体的信息:
展开
代码语言:C++
自动换行
AI代码解释
#include <exception> #include <iostream> using namespace std; class DivideByZero : public exception { public: const char* what() const noexcept override { return "ERROR: Division by zero."; } }; void check(int y) noexcept(false) { if (y == 0) throw DivideByZero(); } int main() { int x = 100, y = 0; try { check(y); cout << x / y; } catch (const DivideByZero& e) { cout << e.what() << "\n"; return -1; } cout << "OK\n"; return 0; }
四、标准异常层次结构
C++定义了一些标准的异常,用于各种场景,他们都是继承自std::exception:

下表是对上面层次结构中出现的每个异常的说明:
|
异常类型 |
描述 |
|---|---|
|
std::exception |
所有标准异常基类 |
|
std::bad_alloc |
内存分配失败( |
|
std::bad_cast |
动态类型转换失败( |
|
std::bad_typeid |
|
|
std::logic_error |
逻辑错误(可在编译时发现) |
|
├─ std::domain_error |
数学域无效 |
|
├─ std::invalid_argument |
参数无效 |
|
├─ std::length_error |
容器长度超限 |
|
└─ std::out_of_range |
越界访问 |
|
std::runtime_error |
运行时错误(无法编译时检测) |
|
├─ std::overflow_error |
算术溢出 |
|
├─ std::underflow_error |
算术下溢 |
|
└─ std::range_error |
存储超出范围 |
五、std::exception_ptr 与异常传递
根据官方文档的介绍 std::exception_ptr是一个指向 exception object 的共享智能指针。关键在于理解 “exception object” 是什么,是std::exception类的对象吗?这种理解是不准的,按我的理解,所谓“exception object” 应该是被throw抛出的对象,根据我们上面的学习,它既可以是int、double等简单的数据类型、也可以是自定义的类对象,当然也可以是std::exception类对象。
更多推荐



所有评论(0)