【问题标题】:Should I declare a method noexcept if it never throws when used correctly? [duplicate]如果正确使用时它从不抛出,我应该声明一个方法 noexcept 吗? [复制]
【发布时间】:2015-02-22 20:20:45
【问题描述】:

我正在实现一个队列,我想知道,当用户滥用容器时我该怎么办?

例如,我有两个方法 Front 和 Pop,只要不在空队列上调用它们,它们就不会抛出(我 static_assert 所包含元素的析构函数是 noexcept)。如果在空队列上调用它们,我可以对它们添加一个检查,但是我无法定义它们 noexcept。

我认为声明这些 noexcept 是有意义的,然后说在空队列上调用时行为未定义(我提供 Size 和 Empty 方法供用户检查)。然后我可以仅在调试版本上添加检查,因此它会在误用时调用终止调试并尝试在发布时破坏或取消引用丢失的元素。我想知道更好的方法是什么。


在考虑了接受的答案后,我决定遵循标准。 Vector的pop_back没有标记noexcept,和我的Pop具有相同的语义,所以我也不会标记为noexcept。通常,会尽量避免将狭义合同设置为 noexcept。

【问题讨论】:

  • 当队列为空时声明行为未定义可能是有意义的,无论它是否为noexcept。异常不一定是断言不变量的最佳方式。您的最后一段完美地描述了assert 的目的。可能相关:N3963.
  • Effective Modern C++ 的第 14 项的一部分也与这个确切的问题相关,将其与宽合同和窄合同的概念联系起来。

标签: c++ templates exception c++11


【解决方案1】:

这不是一个简单的问题。在一般情况下,在 C++ 中,您会记录您的合同,说明 行为未定义,除非容器非空。这意味着脱离上下文的调用会导致任何可能的行为。在此类接口中使用noexcept 会限制任何可能行为的范围:它是不涉及跨边界抛出异常的任何可能行为。

为什么这很重要?在我工作的地方,我们使用BSL,它大致是一个扩展的 C++03 标准库的实现。该库的一部分包括用于防御性编程和测试的实用程序。该库没有使用assert,而是使用自己的断言BSLS_ASSERT 宏来验证合同违规。该库的构建使得用户代码可以控制触发断言时发生的情况,并且在测试驱动程序中有效地用于验证不仅是积极行为(组件做它应该做的事情)和消极行为(它不做它应该做的事情)不应该)而且它对违反合同的行为进行了适当的检查。为此,使用了一个抛出特定形式异常的断言处理程序,然后测试驱动程序可以调用合约并验证组件是否正在检查行为……

冗长的故事,关键是如果具有 narrow 合约的函数(可以在合约外调用)被标记为noexcept,因为实现永远不应该抛出(调用@987654327 @ 在一个容器上),那么在合约外调用时它不能抛出,并且不能使用上述机制来验证组件是否会检测到合约违规。

这是 C++11 标准较晚修订(就在批准之前)以从所有具有狭窄合同的函数中删除 noexcept 的部分原因。你可以在proposal阅读更多内容

【讨论】:

  • 嗯,有趣的论文。我想我看到了那些描述它的人的视频演示,不知道他们已经将它提交给委员会。我决定遵循标准。 Vector的pop_back没有标记noexcept,和我的pop语义一样,所以我也不会标记noexcept。
  • “当被调用时它不能抛出”我不确定我是否同意。只有满足前置条件时,后置条件才会得到保证。当然,认为异常子句约束未定义的行为是很疯狂的。您的示例假定保证可以检测到违反合同的行为,这与“未定义行为”所描述的保证完全不同。
  • @BenVoigt:我来自一个在接口中明确记录 UB 并且检测到超出合同调用的地方。我们的测试驱动程序确保如果我们在生产中遇到此问题,任务将不会继续进行,就好像什么都没发生一样。触发断言时会发生什么取决于main 中的配置,最常见的两种情况是循环旋转,以便有人可以检查程序的状态和中止(为调试而生成的核心文件)。你说得对,UB 意味着任何事情都可能发生,我们只是有严格的检测 UB 政策(在可行的情况下)
  • ... 调试版本允许进行更昂贵的检查,并且在生产中可能会禁用更昂贵的测试,以免影响整体性能。但是在测试期间,在调试版本中,程序是在所有断言的情况下构建的,并且每个组件都经过测试以验证先决条件,从而非常有信心在发布产品之前应该检测到合同外调用。
  • 当引用问题的公认答案(a)在每个细节上都是错误的并且(b)低于这个答案时,他们将这个问题作为“重复”关闭,这很烦人。 StackOverflow 最烦人的故障模式。
猜你喜欢
  • 2020-10-24
  • 2014-03-05
  • 2017-05-22
  • 1970-01-01
  • 2015-10-26
  • 2020-10-18
  • 2012-06-07
  • 1970-01-01
  • 2011-10-09
相关资源
最近更新 更多