C++ 中不可复制的类可以通过值捕获吗?

Fed*_*dor 6 c++ initialization exception language-lawyer copy-initialization

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

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

int main() {
    try {
        throw B{};
    }
    catch( B ) {
    }
}
Run Code Online (Sandbox Code Playgroud)

Clang 拒绝该代码并出现预期错误:

error: call to deleted constructor of 'B'
    catch( B ) {
Run Code Online (Sandbox Code Playgroud)

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

这里是哪个编译器?

son*_*yao 5

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

[例外.投掷]/3

抛出异常会复制初始化 ([dcl.init], [class.copy.ctor]) 一个临时对象,称为异常对象。表示临时的左值用于初始化在匹配处理程序([except.handle])中声明的变量。

[抛出除外]/5

当抛出的对象是类对象时,为复制初始化选择的构造函数以及将抛出的对象视为左值而为复制初始化选择的构造函数应是不可删除和可访问的,即使复制/移动操作被省略([class.copy.elision])。

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

我已将此报告为gcc bug 103048

顺便说一句,由于强制复制省略(C++17 起) ,引起的异常对象的复制初始化throw B{};很好。

在对象的初始化中,当初始化表达式是与变量类型相同的类类型(忽略 cv 限定)的纯右值时:

T x = T(T(f())); // only one call to default constructor of T, to initialize x
Run Code Online (Sandbox Code Playgroud)

首先,如果 T 是类类型并且初始设定项是纯右值表达式,其 cv 未限定类型与 T 相同,则初始值设定项表达式本身(而不是从中具体化的临时值)用于初始化目标对象:请参阅复制省略(C++17 起)

  • 为什么我只是第二个投票者? (2认同)