0%

异常的概念+自带的语法功能

2020年3月16日 下午7:25

异常相关文字概念:

错误处理的两种方式:

  • 返回错误码
  • 异常处理

异常处理

异常处理并不意味着需要写显式的 try 和 catch。异常安全的代码,可以没有任何 try 和 catch

异常安全定义

  • 异常安全,并不是指的不会发生异常,而是发生异常之后也是安全的。这里的安全指:不会发生资源泄漏 + 不会处于一个不一致的状态
  • 异常安全是指当异常发生时,既不会发生资源泄漏,系统也不会处于一个不一致的状态

可能会出现错误 / 异常的地方

  • 首先是内存分配。
    • 如果 new 出错,按照 C++ 的规则,一般会得到异常 bad_alloc,对象的构造也就失败了。这种情况下,在 catch 捕捉到这个异常之前,所有的栈上对象会全部被析构,资源全部被自动清理。
  • 如果是矩阵的长宽不合适不能做乘法呢?
    • 我们同样会得到一个异常,这样,在使用乘法的地方,对象 c 根本不会被构造出来。
  • 如果在乘法函数里内存分配失败呢?
    • 一样,result 对象根本没有构造出来,也就没有 c 对象了。还是一切正常。
  • 如果 a、b 是本地变量,然后乘法失败了呢?
    • 析构函数会自动释放其空间,我们同样不会有任何资源泄漏

异常相关的语法定义:C++自带的功能

noexcept

  • 从 C++17 开始,C++ 甚至完全禁止了以往的动态异常规约,你不再能在函数声明里写你可能会抛出某某异常。你唯一能声明的,就是某函数不会抛出异常——noexcept、noexcept(true) 或 throw()。这也是 C++ 的运行时唯一会检查的东西了。
  • 如果一个函数声明了不会抛出异常、结果却抛出了异常,C++ 运行时会调用 std::terminate 来终止应用程序。不管是程序员的声明,还是编译器的检查,都不会告诉你哪些函数会抛出哪些异常。

标准容器的强异常保证:

  • C++ 的标准容器在大部分情况下提供了强异常保证,即,一旦异常发生,现场会恢复到调用函数之前的状态,容器的内容不会发生改变,也没有任何资源泄漏
  • 前面提到过,vector 会在元素类型没有提供保证不抛异常的移动构造函数的情况下,在移动元素时会使用拷贝构造函数。这是因为一旦某个操作发生了异常,被移动的元素已经被破坏,处于只能析构的状态,异常安全性就不能得到保证了。