从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 的无限制调用进行交换 。a
b
swap
如果
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++ 没有“模式”。