gpt4 book ai didi

c++ - 为什么接受默认的 noexcept 移动构造函数?

转载 作者:行者123 更新时间:2023-12-03 10:03:48 25 4
gpt4 key购买 nike

假设以下 c++17 代码:

#include <type_traits>
namespace dtl
{
struct One
{
explicit One(int);
~One() = default;
One(const One &) = delete;
auto operator=(const One &) -> One & = delete;
auto operator=(One &&) -> One & = delete;
One(One &&); // Throwable, not default;
int m_int;
};
struct Two
{
explicit Two(int);
~Two() = default;
Two(const Two &) = delete;
auto operator=(const Two &) -> Two & = delete;
auto operator=(Two &&) noexcept -> Two & = delete;
Two(Two &&) noexcept = default;
One m_one;
};
One::One(One &&) { throw 1; }

static_assert(std::is_nothrow_move_constructible_v<Two>);
}
Code at compiler-explorer
这里我们清楚地看到类 One的移动构造函数没有标记为 noexcept。类(class) Two有一个明确要求为 noexcept 的默认移动构造函数。
如果我们检查这段代码,它会使用 GCC 主干、Clang 主干、MSVC 19.28 编译,但会以 MSVC19.24 失败。
我检查了以下来源似乎告诉我 Two 的移动构造函数需要删除:
  • Program with "noexcept" constructor accepted by gcc, rejected by clang
  • 'noexcept = default' compilation error
  • Bug 35204 - std::chrono exception specification of explicitly defaulted default constructor does not match the calculated one

  • CWG issue 1778阅读(N4296 [dcl.fct.def.default]/p3):

    If a function that is explicitly defaulted is declared with an exception-specification that is not compatible (15.4) with the exception specification on the implicit declaration, then

    if the function is explicitly defaulted on its first declaration, it is defined as deleted;otherwise, the program is ill-formed.


    基于这些信息,我只能得出结论,所有 3 个编译器在考虑 Two 时都是错误的。作为 no_throw_move_constructible 并且应该隐式删除移动构造函数。因为这三个人都忽略了这个标准很奇怪,所以我想知道:这真的是编译器错误还是我遗漏了什么。

    最佳答案

    我相信您正在查看过时的信息。 DR1778 已被 P1286R2 取代.如果你看 implementation status ,你会看到 gcc 10 和 clang 9 实现了这个新决议。
    事实上,如果你回到 godbolt 中旧的 gcc 版本,它会告诉你:

    <source>: In function 'int main()':
    <source>:35:25: error: use of deleted function 'dtl::Two::Two(dtl::Two&&)'
    35 | auto b = std::move(a);
    | ^
    <source>:23:7: note: 'dtl::Two::Two(dtl::Two&&) noexcept' is implicitly deleted because its exception-specification does not match the implicit exception-specification ''
    23 | Two(Two &&) noexcept = default;
    | ^~~
    Compiler returned: 1
    您可以找到 gcc 讨论 here .根据 this list , P1286R2 被接受为 DR,这意味着它追溯适用于以前的标准。因此,较新的编译器将以您注意到的方式运行,独立于所选的 C++ 标准。
    但是,在运行时,这将按预期失败:
    dtl::One::One(int) {};
    dtl::Two::Two(int) : m_one(0) {};

    int main() {
    auto a = dtl::Two{1};
    try {
    auto b = std::move(a);
    } catch (...) {
    // Even though an exception is thrown, it will not be caught here because
    // we broke our `noexcept` promise.
    std::cout << "caught" << std::endl;
    }
    return 0;
    }
    [:~/tmp] $ /usr/local/Cellar/llvm/11.0.0/bin/clang++ -std=c++17 mv.cpp  && ./a.out
    libc++abi.dylib: terminating with uncaught exception of type int
    Abort trap: 6

    关于c++ - 为什么接受默认的 noexcept 移动构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65521419/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com