不可复制的 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 的评论。)
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]).
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)
在下一个程序中,删除了复制构造函数的结构 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 的评论。)
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]).
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)