【问题标题】:Why is basic_string::swap not noexcept?为什么 basic_string::swap 不是 noexcept?
【发布时间】:2013-05-13 20:14:57
【问题描述】:

我刚刚发现 basic_string 的两个交换函数(成员函数和命名空间 std 中的函数)没有用 noexcept 声明——既不是在 GCC-4.8 的标准库中,也不是在最新的C++ 草案 N3690。

另一方面,移动构造函数和移动赋值运算符是用noexcept 声明的。这说明应该可以提供noexcept交换函数。

问题:没有用 noexcept 声明交换函数的原因是什么?

更新:问题是我想在我自己的交换函数中使用一个模板函数,它使用 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 则不是这样。

【问题讨论】:

  • 也许这只是一个疏忽。 basic_string<>::swap 的规范确实声明 Throws: Nothing.

标签: c++ c++11


【解决方案1】:

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)。 — 尾注]

3 返回:*this.

如果swap(str) 应该是assign() 的有效实现,并且assign() 被无条件标记为noexcept,那么假设swap() 也是noexcept 是有意义的。

【讨论】:

  • "Throws: Nothing" 与当前标准中的 noexcept 不同。如果函数具有先决条件,并且调用违反了这些先决条件,则会导致未定义的行为,允许实现抛出异常。如果先决条件函数声明为 noexcept,则该异常将导致 terminate() 而不是传播。但是,string::swap 没有列出任何先决条件,这意味着这看起来确实是个错误。我们需要检查分配器的传播交换规则以确定。
  • 我在问题中添加了一些背景信息。问题是,如果没有 noexcept,我的函数模板中的 static_assert 检查会失败。当然有一个简单的解决方法:我可以为 basic_string 重载函数模板。但我对不存在 noexcept 的原因感兴趣。
  • @Jeffrey Yasskin 规范是否允许noexcept 函数在不调用std::terminate() 的情况下抛出异常?
猜你喜欢
  • 1970-01-01
  • 2016-11-21
  • 1970-01-01
  • 1970-01-01
  • 2018-07-11
  • 2020-09-10
  • 2019-04-23
  • 2015-01-03
  • 2015-12-14
相关资源
最近更新 更多