为什么STL容器中的交换成员函数没有声明为noexcept?

13

截至N3797版本,C++标准要求容器的swap函数不抛出异常,除非特别指定[container.requirements.general]23.2.1§10)。

  • 为什么被指定不抛出异常的swap成员函数没有声明为noexcept

同样的问题也适用于专门的非成员swap重载。


我猜他们可能错过了。 - Nawaz
你正在使用哪个C++库? - Mats Petersson
1
@MatsPetersson 我只是在看裸标准,而不是特定的实现。 - Ralph Tandetzky
2
这可能会有帮助:链接 - ForEveR
1
@ForEveR:我将其复制到答案中,以便它在此问答中正式存在。 - Lightness Races in Orbit
显示剩余2条评论
2个回答

10

refp所说的基础上,以下是来自Daniel Krügler在std-discussion邮件列表上的文章:

将函数声明为无条件noexcept的内部策略解释在

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3279.pdf

在该文中使用的术语,std::vector的swap函数具有收缩合同,即它对参与对象的分配器有前提条件。这意味着调用者可能会违反前提条件,并且实现应允许通过不同于终止的方式来发出信号。因此,这样的函数不应该是noexcept,但是它应该具有一个有效的元素 "Throws: Nothing",因为这适用于满足前提条件的情况。

(链接)

所述的内部政策是您问题的规范和官方答案。


1
如果调用者违反了前置条件,那不就是一个明显的错误吗?如果调用者假设swap()函数不会抛出异常,但它仍然抛出异常(因为前置条件被违反),那么异常安全和不变量保持都将无从谈起。程序最好直接终止。 - Ralph Tandetzky
@RalphTandetzky:是的,实现可以这样做。标准是对这样的程序不提出任何要求。没有要求。没有。 - Lightness Races in Orbit

6

起初听起来可能有些奇怪,但不明确说明标准容器的swap是否为noexcept是有意的;这一切都归结于未定义行为(UB)。



23.2.1p9 通用容器要求 [container.requirements.general]

对于除了array以外的标准容器类型ab,表达式a.swap(b)将交换ab的值,而不会在各个容器元素上调用任何移动、复制或交换操作。

属于ab的任何ComparePredHash对象都应该是可交换的,并且应该通过非成员swap进行交换。

如果allocator_traits<allocator_type>::propagate_on_container_swap::valuetrue,则ab的分配器也应该通过非成员swap进行交换。否则,除非`a.get_allocator() == b.get_allocator()`,否则它们不应该被交换,行为未定义。

注意:由我添加的斜体字


为什么前面的部分与我的问题相关?

由于标准容器的swap具有前提条件(最重要的是标准先前引用的最后一段),如果不满足可能会导致UB,因此标准不想对实现施加“不可能”的约束。


标准对于“未定义行为”有以下规定:
1.3.24 未定义行为 [defns.undefined]
本国际标准未强制执行的行为。

只有罪犯和销售员可能认为“不”是其他东西,但当标准说“没有要求”时,它确实意味着“没有要求”;将相关的swap函数标记为noexcept会对实现施加要求,而实际上应该没有要求。


为什么标准不想强制执行这些要求?

关于这个问题,有一篇有趣的论文(N3248),作者是Alisdair MeredithJohn Lakos,题为"noexcept prevents Library Validation"。

简而言之,它讲述了如何使用noexcept将阻止库实现在库代码(即标准库的实现)中使用asserts,即使在调试模式下也是如此,并且这样做的影响。

如果C++有一个标准化的"测试" vs "生产"模式(正如论文所称),其中noexcept会有条件地应用,那么这将大大减少问题。但目前情况是:C++没有"模式"。


为什么在交换分配器和数据时会出现问题? - GreenScape
这是对UB定义的有趣看法。并不是说它是错误的。 - Lightness Races in Orbit
@GreenScape 我会将你的评论/问题分叉成一个新的问答,当它可用时我会通知你。 - Filip Roséen - refp
@GreenScape 这应该能回答你的问题:为什么涉及分配器时交换标准库可能会有问题? - Filip Roséen - refp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接