【问题标题】:Why is swapping multidimensional arrays not noexcept?为什么交换多维数组不是noexcept?
【发布时间】:2015-01-03 19:35:01
【问题描述】:

我有以下sn-p:

#include <algorithm>
#include <iostream>

int main(int argc, char** argv) {
    int x[2][3];
    int y[2][3];

    using std::swap;
    std::cout << noexcept(swap(x, y)) << "\n";

    return 0;
}

使用 GCC 4.9.0,这将打印 0。我不明白为什么。

根据标准,std::swap 有两个重载:

namespace std {
    template<class T> void swap(T& a, T& b) noexcept(
        is_nothrow_move_constructible<T>::value &&
        is_nothrow_move_assignable<T>::value
    );

    template<class T, size_t N>
    void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b)));
}

据我了解,数组的 noexcept 说明符应该递归地用于多维数组。

为什么交换多维数组不是noexcept


在试图找到一个仍然行为怪异的最小示例时,我想出了以下内容:

#include <iostream>

template<class T> struct Specialized      : std::false_type {};
template<>        struct Specialized<int> : std::true_type  {};

template<class T>                void f(T& a) noexcept(Specialized<T>::value);
template<class T, std::size_t N> void f(T (&a)[N]) noexcept(noexcept(f(*a)));

int main(int argc, char** argv) {
    int x, y[1], z[1][1];

    std::cout << noexcept(f(x)) << " "
              << noexcept(f(y)) << " "
              << noexcept(f(z)) << "\n";
}

使用 GCC 4.9.0 打印 1 1 0,但我还是不明白为什么。

【问题讨论】:

  • 对我来说似乎很奇怪。我在 libstdc++ 中发现 DR 809 其中 appearsimplemented 所以这个 bug 可能在别处。根据您的最新编辑,clang 也会打印出1 1 0。用 libc++ 打印 0 为原始的 sn-p。
  • 在通过调试器运行它后,对于 libstdc++,它会经历 std::swapstd::move 的重载,标记为 noexcept。 clang 和 g++ 对完全相同的库代码有不同的结果这一事实让我大吃一惊。请注意,noexcept 甚至不会生成 std::swap 的代码。

标签: c++ swap noexcept


【解决方案1】:

这个重载:

template<class T, size_t N>
void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b)));

直到; 才在范围内,因此swap(*a, *b) 不考虑此重载。这是因为:

3.3.2/1 名称的声明点紧接在其完整声明符之后(第 8 条)和初始化器之前(如果有的话)……

异常规范是声明器的一部分。

【讨论】:

  • 这似乎是标准中相当严重的疏忽。在其当前形式中,朴素的递归 noexcept 声明不起作用。更糟糕的是,标准本身使用了这些幼稚的递归声明。
  • 告诉圣诞老人;他会把 Bjarne 列入淘气名单。
  • @FrankHB 这个问题比缺陷早一周。
  • 对于 2021 年偶然发现此问题的任何人,已修复:cplusplus.github.io/LWG/issue2554
猜你喜欢
  • 2013-05-13
  • 1970-01-01
  • 2020-09-10
  • 1970-01-01
  • 2016-11-21
  • 1970-01-01
  • 2018-07-11
  • 2011-06-06
  • 2012-10-06
相关资源
最近更新 更多