c++ - 不可复制的类可以在 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 的评论。)
抛出异常复制初始化 ([dcl.init], [class.copy.ctor]) 一个临时对象,称为异常对象。表示临时值的左值用于初始化匹配处理程序中声明的变量([except.handle])。
当抛出的对象是类对象时,为复制初始化选择的构造函数以及为复制初始化选择的构造函数将抛出的对象视为左值,即使复制/移动操作也应不可删除且可访问被省略([class.copy.elision])。
异常对象被认为是一个左值,在catch子句的参数的复制初始化中,选择了复制构造函数。复制操作可能会被忽略为优化;但是复制构造函数仍然必须存在并且可以访问。
我已将此报告为gcc bug 103048。
顺便说一句,由于强制复制省略(自 C++17 起) ,导致的异常对象的复制初始化throw B{};
很好。
在对象的初始化中,当初始化表达式是与变量类型相同的类类型(忽略 cv-qualification)的纯右值时:
T x = T(T(f())); // only one call to default constructor of T, to initialize x
首先,如果 T 是一个类类型并且初始化器是一个纯右值表达式,其 cv 非限定类型与 T 相同,则初始化器表达式本身,而不是从它的临时物化,用于初始化目标对象:见复制省略(C++17 起)
推荐阅读
- excel - 分配给 Excel 中的图形图标时,宏无法正常工作。但它在通过 VBA IDE 运行时工作
- sqlite - 从 SQLite 中的两个表中随机选择
- c# - 按下 Arduino 按钮后如何在 C# 应用程序上执行操作?
- c# - 如何在 xamarin android 中使用这个库(smarteist Android-Image-Slider)?
- thorntail - 如何在 thorntail 中设置相对路径日志记录?
- kotlin - Kotlin Flow 的 GroupBy 运算符
- bash - Ultisnips 中的制表位无法与 zsh 一起正常工作
- resources - 迭代 puppet 资源收集器
- regex - 正则表达式 url 参数 IIS
- reactjs - 将提交的表单数据传递给另一个组件