2

尽管该主题已在 SO 上进行了广泛讨论,但考虑到以下事实,我想澄清一些我仍然不清楚的事情:

  1. 10 年前,Herb Sutter 告诉我们不要使用此功能

  2. 指定函数/方法可能抛出的可能异常不会迫使编译器在您决定更改函数的主体并抛出新类型的异常时对您大喊大叫,从而错误地忘记更改函数声明中的异常规范。

  3. 如果你有一个非常高级的函数调用其他几个高级函数,每个函数都运行大量代码来产生结果,那么我可以想象地狱噩梦的维护,当我必须指定第一个函数的所有错误时可能会抛出,并且这个列表必须包括内部函数可能抛出的所有异常等等,从而在高级和低级函数之间产生紧密耦合,这是非常不可取的。另一方面,我们从 std::runtime_error 派生所有异常,我们知道这是一个好习惯我们可以指定高级函数只抛出 std::runtime_error 并完成它。但是等一下……我们实际上在哪里捕获异常?当高级函数应该只抛出 std::runtime_error 时,将对这些高级函数之一的调用包含在 try / catch 块中会不会很奇怪/讨厌/不好,该块会捕获 MyVerySpecific 异常? ? 在较低级别的函数中捕获特定异常是否有好处,这些函数无法对它们做任何事情,而是将它们传递到更通用的容器中,并附加更多信息?我当然不想在我编写的每个函数中都编写 try / catch 块,只是为了格式化异常。这就像要求每个函数都验证它的参数,这会让人发疯,

问题:

  1. Herb Sutter 关于异常规范的咆哮今天仍然成立吗?从那以后有什么改变吗?我最感兴趣的是 pre-C++0x 标准。如果是,我想我们可以考虑关闭这个话题。

  2. 由于编译器似乎大多忽略了这些异常规范,并且在捕获异常时,在 99% 的情况下,人们会使用catch (const CustomException &ex),如何指定函数抛出 CustomException?throw(CustomExecption)throw (CustomException &)throw (const CustomException &)? 我已经看到了所有的变化,虽然我会选择第一个,但其他的有什么意义/增加任何好处吗?

  3. 人们将如何实际使用此功能,同时避免上述第三个事实中说明的谬误?

  4. 编辑:假设我们正在建立一个图书馆。如果我们不使用异常规范,它的用户将如何知道预期的异常?他们肯定不会看到 API 方法会在内部调用哪些函数……

4

2 回答 2

2

1/ Herb Sutter 关于异常规范的咆哮今天仍然成立吗?从那以后有什么改变吗?我最感兴趣的是 pre-C++0x 标准。如果是,我想我们可以考虑关闭这个话题。

是的,他们仍然坚持。

例外规范是:

  • 中途实现(例如,函数指针未指定异常)
  • 在编译时未检查,但在运行时导致终止!

一般来说,我会反对异常规范,因为它会导致实现细节的泄漏。查看 Java 异常的状态...

特别是在 C++ 中?异常规范就像是在踢自己的脚,因为文档中最微小的错误可能会导致std::terminate调用。请注意,几乎所有函数都可能抛出例如 astd::bad_alloc或 a std::out_of_range

注意:由于 C++11throw()已被弃用,现在使用 C++17 它已不复存在;相反,从 C++17 开始,noexcept(false)可以使用说明符。它在函数指针中得到更好的支持,但仍会导致运行时终止,而不是编译时出错。


2/ 由于编译器似乎大多忽略了这些异常规范,并且在捕获异常时,在 99% 的情况下,人们会使用 catch (const CustomException &ex),那么如何指定函数抛出 CustomException?throw(CustomExecption) 还是 throw (CustomException &) 还是 throw (const CustomException &)?我已经看到了所有的变化,虽然我会选择第一个,但其他的有什么意义/增加任何好处吗?

编译器不会忽略异常规范,它会设置非常警惕的看门狗(哪些轴)以确保在您错过某些内容时终止您的程序。


3/ 如何实际使用此功能,同时避免上述第三个事实中说明的谬误?

如果它保持非正式,您的客户会很感激,所以最好的例子是:

void func(); // throw CustomException

这使您可以专注于也很重要的异常,并让“不重要”的异常溜走。如果消费者想要它们全部?catch(std::exception const& e)作品。


4/ 编辑:假设我们正在建立一个图书馆。如果我们不使用异常规范,它的用户将如何知道预期的异常?他们肯定不会看到 API 方法会在内部调用哪些函数……

他们必须吗?

记录重要的事情,std::exception...处理意外情况。

于 2012-06-15T14:26:34.867 回答
0
  1. Herb Sutter 关于异常规范的咆哮今天仍然成立吗?从那以后有什么改变吗?

我不会称之为咆哮。他只是指出了与异常规范相关的问题。

是的,它仍然成立。如文中所述,如果抛出未指定的异常,程序将终止,这对于 99% 的应用程序来说是不可接受的。

  1. 如何指定一个函数抛出 CustomException?
class A
{
 //...
   void foo() throws( CustomException );
};
  1. 人们将如何实际使用此功能,同时避免上述第三个事实中说明的谬误?

通过查看函数声明,用户知道可以抛出哪些异常。问题是当需要抛出新异常时,所有函数声明都需要更改。

  1. 假设我们正在构建一个库。如果我们不使用异常规范,它的用户将如何知道预期的异常?

通过阅读文档。

于 2012-06-15T14:06:20.567 回答