为什么basic_string::swap不是noexcept的?

23

我刚发现基本字符串的两个交换函数(成员函数和std名称空间中的函数)都没有用noexcept声明——无论是在GCC-4.8的标准库中还是最新的C++草案N3690中。

另一方面,移动构造函数以及移动赋值运算符却被声明为noexcept。这表明应该可以提供支持noexcept的swap函数。

问题:为什么没有将swap函数声明为noexcept

更新:问题在于我想在自己的swap函数中使用一个模板函数,该函数使用static_assert来检查交换是否实际上是noexcept的,例如:

struct foo {
    bar_t bar;
    baz_t baz;
    void swap(foo& rhs) noexcept {
        swap_noexcept(bar, rhs.bar);
        swap_noexcept(baz, rhs.baz);
    }
};

然而,这仅在声明交换函数时使用 noexcept 才有效,而对于 basic_string 就不是这种情况。


2
也许这只是一个疏忽。basic_string<>::swap 的规范确实声明了_Throws: Nothing._ - K-ballo
1个回答

21

C++11标准的第21.4.6.8段规定:

21.4.6.8 basic_string::swap [string::swap]

void swap(basic_string& s);

1 后置条件: *this 包含与 s 相同的字符序列,s 包含与 *this 相同的字符序列。

2 抛出异常: 无

3 复杂度: 常数时间。

因此,人们必须得出没有 noexcept 是一个疏忽。

另一个线索可以在关于 assign() 成员函数的第21.4.6.3段中找到:

basic_string& assign(basic_string&& str) noexcept;

效果:该函数将由* this控制的字符串替换为一个长度为str.size()且元素为由str控制的字符串的副本的字符串。[注意:有效的实现是swap(str)。--end note]

3 返回* this。

如果假定swap(str)assign()的有效实现,并且将assign()标记为无条件的noexcept,则可以合理地假设swap() 也是noexcept的。


2
"Throws: Nothing"在当前标准中与noexcept不同。如果一个函数有前置条件,并且调用违反了这些前置条件,那么会导致未定义的行为,实现可以抛出异常。如果前置条件满足的函数被声明为noexcept,那么该异常将导致terminate()而不是传播。然而,string::swap没有列出任何前置条件,这意味着这可能是一个错误。我们需要检查分配器的传播规则以确保。 - Jeffrey Yasskin
我已经在问题中添加了一些背景信息。问题是,在没有 noexcept 的情况下,我的函数模板中的 static_assert 检查失败了。当然,有一个简单的解决方法:我可以为 basic_string 重载函数模板。但我对不存在 noexcept 的原因感兴趣。 - nosid
2
@Jeffrey Yasskin 根据规范,当发生未定义行为时,noexcept 函数是否允许在不调用 std::terminate() 的情况下抛出异常? - Zyx 2000

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