// c++中的异常处理
// 1.throw : 专门用于抛出异常,做出提示
// 2.try : 尝试运行可能会异常的代码
// 3.catch : 用于接收前面跑出来的异常并进行解决
// 执行循序为:
// try
// {
// throw ...; // 执行的代码中必须直接或者间接的有throw
// }
// catch在throw之后执行,catch执行的数据类型入参与throw抛出异常的数据类型一致
// catch(const std::exception& e)
// {
// std::cerr << e.what() << '\n';
// }
// try
// {
// do th1 ... (必须会执行的代码)
// 直接或间接有throw,
// 如果此处没有触发throw则会执行下文的do th2
// 如果此处有触发throw,则下文的do th2不会继续执行,而是之下下文中的chtch
// 因为如果触发throw,则do th2没有继续执行的必要
// do th2 ... ()
// }
// // const std::exception& e为接收到的异常情况
// catch(const std::exception& e)
// {
// // 异常处理
// std::cerr << e.what() << '\n';
// }
// 以上的try catch可以层层嵌套使用
// 在 C++ 中,可以通过嵌套 `try-catch` 来处理更复杂的异常情况,即在一个 `try` 块中嵌套另一个 `try` 块。
// 在嵌套结构中,内部的 `try` 块可以处理外部 `try` 块无法处理的异常。
// 下面是一个嵌套 `try-catch` 的示例代码:
// try {
// try {
// // Block of code which may throw an exception
// } catch (const SomeExceptionType& e) {
// // Exception handling code for inner try block
// }
// // Block of code which may throw another exception
// } catch (const AnotherExceptionType& e) {
// // Exception handling code for outer try block
// }
// 在上面的代码中,有两个 `try` 块,其中内部的 `try` 块包含一个代码块,可能会引发某种类型的异常。
// 如果在内部的 `try` 块中抛出异常,它将被内部的 `catch` 块捕获和处理。
// 如果在内部的 `try` 块中未发生异常,则执行内部 `try` 块后的代码块。
// 如果在这个代码块中引发了异常,那么这个异常将被外部的 `catch` 块捕获和处理。
// 需要注意的是,如果一个 `catch` 块捕获了异常,它将防止此异常进一步传播到该代码块之外。
// 因此,如果一个 `catch` 块在处理异常时,抛出了另一个异常,则外部的 `catch` 块将无法捕获最初被抛出的异常,
// 也就是说,只有最内层的 `catch` 块可以捕获到抛出的异常。
// 注意:
// 只要有throw抛出了异常,后边就必须有catch就就收异常进行异常处理,这是语法规定。
#include <iostream>
#include <string>
using namespace std;
int test(int a, int b)
{
// 当b==0时,正常的处理已经不能继续,必须进行异常处理
if (b == 0.0)
{
// 有异常情况->需要通过throw进行报告
// 通过throw + 抛出的异常信息;
// 抛出的异常信息:支持多种类型
throw "这里有问题!";
// 第一个throw抛出异常后,后边的throw不会再继续执行,因为已经没有意义
// 注意:throw不是return,如果这里有throw,则在后边的代码实现中必须要有catch进行异常处理
throw 666;
// 如果char数据类型报错信息后没有对应数据类型的catch处理函数,那么将会出现如下报错
// terminate called after throwing an instance of 'char'
// Aborted (core dumped)
throw 'S';
// 如果double数据类型报错信息后没有对应数据类型的catch处理函数,那么将会出现如下报错
// terminate called after throwing an instance of 'char'
// Aborted (core dumped)
throw 3.14;
}
return a / b;
}
int main()
{
// 异常情况,num没有初始化
int num;
int val = num;
try
{
cout << test(9, 0) << endl;
}
// const std::exception& e参数类型为throw抛出异常时对应的参数类型
// 参数 `const std::exception& e` 表示捕获任何派生自 `std::exception` 类的异常对象
// `std::exception` 是 C++ STL 标准库中所有异常类型的基类,它定义了一些常用的成员函数和属性,
// 例如 `what()` 函数,可以用于获取异常对象的描述信息。
// 派生自 `std::exception` 的标准异常类包括 `std::runtime_error`、`std::logic_error` 和 `std::bad_alloc` 等。
// 使用 `catch(const std::exception& e)` 的语法,表示捕获所有继承自 `std::exception` 的异常类型,
// 以确保我们能够捕获可能发生的异常,并提供恰当的异常处理机制。
// 需要注意的是,不是所有异常都派生自 `std::exception`,例如内存访问错误、空指针异常等异常就不属于该类型。
// 此时,我们需要使用其他适当的异常类来捕获这些异常。
// 另外,如果你想自定义异常,可以使用继承自 `std::exception` 的新类,并为它提供自己的行为和描述信息。
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
// 此处catch处理的异常信息为throw抛出异常时的char *类型异常信息
catch (const char * str) {
cout << str << endl;
}
// 此处catch处理的异常信息为throw抛出异常时的int类型异常信息
catch (int num) {
cout << num << endl;
}
// "..."适配所有数据类型的异常信息
// 比如上文中的throw 3.14;并没有对应的catch函数,
// 那么如果throw 3.14;抛出将会在此处的catch (...)处理
catch (...) {
cout << "有问题" << endl;
}
return 0;
}
c++自定义异常来自于c++标准提供的类:
// c++自定义异常处理类
// 自定义异常处理语法格式:try { throw } catch (const MyExpection& obj) {}
#include <iostream>
#include <exception>
using namespace std;
// std::exception为c++标准异常处理的共同父类,可以使用该类派生出子类实现自定义异常处理
class MyExpection : public std::exception
{
public:
// const char *what const {}
// 以上定义方法会报错:
// error: looser throw specifier for ‘virtual const char* MyExpection::what() const’
// error: overriding ‘virtual const char* std::exception::what() const noexcept’
// what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
// 这个错误是因为虚函数 `what()` 的异常规范(或 throw specifier)与被覆盖的基类中的不同导致的。
// 异常规范告诉编译器,在函数抛出的异常类型方面可以期望什么。
// 在这里,`const char* MyExpection::what() const` 声明的异常规范应该与 `std::exception::what()` 的规范保持一致。
// 在 C++11 中,标准库异常类的 `what()` 声明是 `virtual const char* what() const noexcept`。
// `noexcept` 告诉编译器,该函数不会抛出任何异常。
// 因此,在自定义异常中,需要将 `what()` 函数的异常规范改为 `noexcept`,以与基类中的异常规范保持一致。
// 此外,也可以忽略异常规范,这意味着函数可以抛出任何异常,包括派生自 `std::exception` 的异常类型。
// 不过,需要注意的是,忽略异常规范可能会影响代码的可移植性,因为某些编译器可能依赖于异常规范进行一些优化。
// 如果你决定忽略异常规范,请确保在实际编译器中测试你的代码。
// 修复后的代码如下:
const char *what() const noexcept override {
return "exception !!!";
}
};
int main()
{
// 可以转到exception类中定义查看具体实现和使用接口
MyExpection obj;
cout << obj.what() << endl;
try {
throw MyExpection();
} catch(const MyExpection& obj) {
std::cerr << obj.what() << '\n';
}
return 0;
}