如果正确使用它从不抛出,我应该声明一个方法noexcept吗?

时间:2014-12-24 19:46:28

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

我正在实施队列,我想知道,当用户误用容器时我该怎么办?

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

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


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

1 个答案:

答案 0 :(得分:8)

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

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

冗长的故事,关键在于,如果具有 narrow 契约的函数(可以在合同之外调用)被标记为noexcept,因为实现应该永远不会抛出(调用front()在容器上),然后在调用不合同时它不能抛出,并且上述机制不能用于验证组件是否会检测合同违规。

这是对C ++ 11标准进行后期修订(在批准之前)的一部分原因,即从具有窄合同的所有函数中删除noexcept。您可以在此proposal

中阅读更多内容