不可复制的 class 可以被 C++ 中的值捕获吗?

Can not-copyable class be caught by value in C++?

在下一个程序中,删除了复制构造函数的结构 B 被抛出并被值捕获:

struct B {
    B() = default;
    B(const B&) = delete;
};

int main() {
    try {
        throw B{};
    }
    catch( B ) {
    }
}

Clang 拒绝带有预期错误的代码:

error: call to deleted constructor of 'B'
    catch( B ) {

但是 GCC 很好地接受了程序,演示:https://gcc.godbolt.org/z/ed45YKKo5

这里是哪个编译器?

叮当是正确的。 (感谢@NathanOliver 的评论。)

[except.throw]/3

Throwing an exception copy-initializes ([dcl.init], [class.copy.ctor]) a temporary object, called the exception object. An lvalue denoting the temporary is used to initialize the variable declared in the matching handler ([except.handle]).

[except.throw]/5

When the thrown object is a class object, the constructor selected for the copy-initialization as well as the constructor selected for a copy-initialization considering the thrown object as an lvalue shall be non-deleted and accessible, even if the copy/move operation is elided ([class.copy.elision]).

异常对象被认为是一个左值,在catch子句的参数的复制初始化中,选择了复制构造函数。复制操作可能会作为一种优化而被省略;但是复制构造函数仍然必须存在并且可以访问。

我已将此报告为 gcc bug 103048

顺便说一下 copy-initialization of the exception object caused by throw B{}; is fine because of mandatory copy elision(C++17 起)。

In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:

T x = T(T(f())); // only one call to default constructor of T, to initialize x

First, if T is a class type and the initializer is a prvalue expression whose cv-unqualified type is the same class as T, the initializer expression itself, rather than a temporary materialized from it, is used to initialize the destination object: see copy elision (since C++17)