【发布时间】:2012-06-15 13:25:11
【问题描述】:
虽然这个话题已经在 SO 上进行了广泛的讨论,但考虑到以下事实,我想澄清一些我仍然不清楚的事情:
10 年前,Herb Sutter 告诉我们refrain from using this functionality。
指定函数/方法可能抛出的可能异常不会强制编译器在您决定更改函数体并抛出新类型的异常时对您大喊大叫,错误地忘记更改异常规范在函数的声明中。
1234563第一个函数可能抛出的错误,这个列表必须包括内部函数可能抛出的所有异常等等,从而在高级和低级函数之间产生紧密耦合,这是非常不可取的。另一方面,我们从 std::runtime_error 派生所有异常,we know is a good practice 并且我们可以指定高级函数只是抛出 std::runtime_error 并完成它。但是等一下……我们实际上在哪里捕获异常?当高级函数应该只抛出 std::runtime_error 时,将对这些高级函数之一的调用包含在 try / catch 块中会不会很奇怪/讨厌/不好,该块会捕获 MyVerySpecific 异常? ?在较低级别的函数中捕获特定异常是否有好处,这些函数无法对它们做任何事情,而是将它们传递到更通用的容器中,并附加更多信息?我当然不想在我编写的每个函数中都编写 try / catch 块,只是为了格式化异常。这就像要求每个函数都验证其参数一样,当人们需要更改低级函数中的某些内容时,这会让人发疯。
问题:
Herb Sutter 关于异常规范的咆哮今天仍然成立吗?从那以后有什么改变吗?我最感兴趣的是 pre-C++0x 标准。如果是,我想我们可以考虑关闭这个话题。
由于编译器似乎大多忽略了这些异常规范,并且在捕获异常时,在 99% 的情况下会使用
catch (const CustomException &ex),那么如何指定函数抛出 CustomException?throw(CustomExecption)或throw (CustomException &)或throw (const CustomException &)?我已经看到了所有的变化,虽然我会选择第一个,但其他的有什么意义/增加任何好处吗?如何实际使用此功能,同时避免上述第三个事实中说明的谬误?
编辑:假设我们正在构建一个库。如果我们不使用异常规范,它的用户将如何知道预期的异常?他们肯定不会看到 API 方法会在内部调用哪些函数...
【问题讨论】:
-
现在和当时一样,异常规范已在 C++11 中明确弃用。取而代之的是
noexcept,这与这类系统一样健全。 -
感谢您的拼写更正:D 我根据您的评论添加了一个附加问题。
-
那么,如何使用该库?就个人而言(您可能会觉得这有点自虐),但我一直认为通用库应该有一个简单的旧 C 接口,其中包含结构和枚举,仅此而已。返回错误代码而不是抛出异常。当然,用 C++ 使用它很痛苦,但它使得在任何其他语言中使用它都变得微不足道。然后他们可以浏览错误代码列表,看看会发生什么。这也让您可以在内部使用您喜欢的任何疯狂的编程风格。只是一个想法。
-
虽然这听起来不错,但老实说,我不愿意实施它。我认为我们应该指导每个人做得更好,而不是永远传播这些旧的做法......想想这让我畏缩,让我想起我写
void main ()时的“美好时光”一切,因为那时我不知道更好...... -
具有 C 接口的 DLL 可以使用合适的符号提取器轻松检查其功能。我可以使用(比如说)C# p/invoke 直接与它交谈,而无需额外的粘合逻辑。我不需要知道它是用什么语言编写的,也不需要知道它对异常的作用。这些都是好事。如果您正在编写一个专门的仅 C++ 库,那么您当然也可以端到端使用 C++。在这种情况下,您不妨将文档和自定义异常类粘贴到共享头文件中。
标签: c++ design-patterns exception exception-handling try-catch