从N3797 开始,C++ 标准要求swap容器的函数不抛出任何异常,除非另有说明[container.requirements.general](23.2.1§10)。
- 为什么
swap指定不抛出的成员函数没有声明noexcept?
同样的问题也适用于专门的非成员swap重载。
除了refp 所说的,这里是 Daniel Krügler 在std-discussion邮件列表中的帖子:
将函数声明为无条件 noexcept 的内部策略在
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3279.pdf
使用该论文中使用的术语,std::vector 的交换函数有一个收缩契约,即它对参与对象的分配器具有先决条件。这意味着,调用者可能会违反先决条件,并且应该允许实现以与终止不同的方式表示这一点。因此,此类函数不应为 noexcept,而应具有有效元素“Throws: Nothing”,因为这适用于满足前提条件的情况。
(链接)
所述内部政策是对您问题的规范、官方回答。
一开始可能听起来很奇怪,但没有明确说明swap标准容器noexcept是故意的;这一切都归结为未定义的行为(UB)。
23.2.1p9一般容器要求[container.requirements.general]
a.swap(b)用于容器a和b除 之外的标准容器类型的表达式array应交换 和 的值,a而不b会对各个容器元素调用任何移动、复制或交换操作。属于and的任何
Compare,Pred或Hash对象都应是可交换的,并且应通过对 non-member 的无限制调用进行交换 。abswap如果
allocator_traits<allocator_type>::propagate_on_container_swap::value是true,则 和 的分配器a也b应使用对 non-member 的无条件调用来交换swap。否则,它们不应被交换,并且行为未定义,除非`a.get_allocator() == b.get_allocator()。
注意:斜体由我添加。
为什么上一部分与我的问题相关?
由于swap标准容器有一个前提条件(最重要的是标准前面引用部分的最后一段),如果不满足可能会导致UB,标准不想对实现施加“不可能”的约束。
该标准对未定义的行为说了以下内容:
1.3.24未定义的行为[defns.undefined]本国际标准没有要求的行为。
只有犯罪分子,也许还有推销员,才会认为No不是No,但是当标准说“没有要求” 时,它实际上意味着“没有要求”;swap将相关功能标记为noexcept将对实现提出要求,而应该没有。
为什么标准不想强加这样的要求?
Alisdair Meredith和John Lakos就此事发表了一篇有趣的论文 ( N3248 ),标题为“防止图书馆验证”。noexcept
简而言之,它讨论了如何noexcept防止库实现asserts在库代码(即标准库的实现)中使用,即使在调试模式下也是如此,以及它的含义。
如果 C++ 有一个标准化的“测试”与“生产”模式(正如论文所说的那样),noexcept那么有条件地适用于哪里,这将是少得多的问题。但就目前而言;C++ 没有“模式”。