C++中带非const引用构造函数的类型能否按值捕获异常?
这属于MSVC的错误诊断,在C++17及更高版本标准下,GCC和Clang的编译行为是符合标准的,示例代码本身合法。
示例代码如下:
struct A { A() {} A(A&) {} A(const A&) = delete; }; int main() { try { throw A{}; } catch( A ) { } }
合法性解释
- throw 阶段的强制复制消除:C17起标准规定了强制复制消除规则,当throw的操作数是纯右值时,编译器必须直接在异常专用存储区构造异常对象,完全跳过拷贝/移动构造函数的调用。因此这一步不需要A的拷贝构造参与,本身合法。如果是C17之前的标准,复制消除属于可选优化,此时
throw A{}需要将纯右值A{}拷贝到异常存储,而纯右值无法绑定到非const左值引用A&,代码才是不合法的。 - 按值捕获的初始化逻辑:catch子句的形参会由异常对象进行拷贝初始化,异常对象本身是非常量左值,
A(A&)构造函数可以完美匹配非常量左值的引用绑定,整个初始化过程完全合法,不需要调用被删除的A(const A&)构造函数。
MSVC的报错逻辑存在缺陷,它默认要求异常类型必须具备可访问的const左值引用拷贝构造函数,没有考虑到非const拷贝构造函数匹配的合法场景,不符合C++17及之后的标准规定。
内容的提问来源于stack exchange,提问作者Fedor。
相关产品推荐
相关产品推荐

