我应该声明一个方法 no除非它在正确使用时永远不会抛出

Should I declare a method noexcept if it never throws when used correctly?

本文关键字:时永 永远 声明 一个 no 方法 我应该      更新时间:2023-10-16

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

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

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


在考虑了接受的答案后,我决定遵循标准。Vector 的pop_back没有标记为 noexcept 并且与我的 Pop 具有相同的语义,所以我也不会将其标记为 noexcept 。一般来说,会尽量避免将狭隘的合同设置为不例外。

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

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

篇大论,重点是,如果具有协定(可以调用非合约)的函数被标记为noexcept,因为实现不应该抛出(在容器上调用front()),那么当调用合约外时,它不能抛出,并且上述机制不能用于验证组件是否会检测到合约违规。

这是 C++11 标准后期修订(就在批准之前)的部分原因,该标准以狭窄的合同从所有功能中删除noexcept。您可以在此提案中阅读更多内容