2 - C++标准异常与noexcept

本文将简要介绍C++的标准异常层次结构,以及noexcept关键字。

标准异常层次结构

C++标准库中抛出的异常都是std::exception为基类的类对象,如图:

利用多态性捕获异常

当使用多条catch子句捕获多种异常时,要捕获的异常应 按子类 -> 基类的顺序出现。例如以下两种写法会带来截然不同的结果:

// 写法1
try
{
    // ...
}
catch (const invalid_argument& e)
{
    // A
}
catch (const exception& e)
{
    // B
}

// 写法2
try
{
    // ...
}
catch (const exception& e)
{
    // B
}
catch (const invalid_argument& e)
{
    // A
}

写法1是正确的,如果捕获了invalid_argument异常,就会执行A;而写法2是错误的,不论捕获什么异常,总会执行B。

noexcept关键字

可以用noexcept标记函数,指出它不抛出任何异常:

void printVal(const vector<int>& values) noexcept;

如果一个函数带有noexcept标记,却以某种方式抛出了异常,C++将调用terminate()来终止程序运行。

还能把noexcept作为运算符使用,格式为noexcept(expression)。有两种用法:

  1. 如果表达式为true,则指定被标记的函数不抛出异常(也就是上边的noexcept其实是noexcept(true));如果表达式为false,则被标记的函数可以抛出任何异常。
  2. 如果表达式被标记为noexcept,会返回true,看看下边的例子:
void f1() noexcept {};
void f2() noexcept(false) {};
void f3() noexcept(noexcept (f1())) {}
void f4() noexcept(noexcept (f2())) {}

int main()
{
    cout << noexcept(f1()) << noexcept(f2()) << noexcept(f3()) << noexcept(f4());
}

输出1010:

  • noexcept(f1())为true:因为f1()被noexcept显式标记。
  • noexcept(f2())为false:因为f2()被noexcept(false)标记。
  • noexcept(f3())为true:因为noexcept(f1())是true。
  • noexcept(f4())为false:因为noexcept(f2())是false。

参考资料

  • 飘零的落花 - 现代C++详解
  • C++20高级编程