在 C++ 中通过 `const` 值捕获异常。编译器存在分歧
在以下程序中,结构体 A
具有复制构造函数 A(const A&)
和来自左值引用 A(A&)
的构造函数>。然后抛出一个 A
对象,然后将其捕获为 const A
:
#include <iostream>
struct A {
A() {}
A(A&) { std::cout << "A(A&) "; }
A(const A&) { std::cout << "A(const A&) "; }
};
int main() {
try {
throw A{};
}
catch ( const A ) {
}
}
所有编译器都接受该程序。
据我了解,异常对象从来都不是 cv 限定的,并且处理程序变量是从引用它们的左值初始化的。因此,我们可以预期 A(A&)
构造函数在 catch
中是首选。 Clang 确实这样做了。
但 GCC 更喜欢复制构造函数打印 A(const A&)
。演示: https://gcc.godbolt.org/z/1an5M7rWh
更奇怪的事情发生在Visual Studio 2019 16.11.7,在程序执行期间不打印任何内容。
这里是哪个编译器?
In the following program, struct A
has both copy-constructor A(const A&)
and a constructor from lvalue-reference A(A&)
. Then an object of A
is thrown and then caught as const A
:
#include <iostream>
struct A {
A() {}
A(A&) { std::cout << "A(A&) "; }
A(const A&) { std::cout << "A(const A&) "; }
};
int main() {
try {
throw A{};
}
catch ( const A ) {
}
}
All compilers accept the program.
As far as I understand exception objects are never cv-qualified, and handler variables are initialized from an lvalue that refers to them. So one could expect that A(A&)
constructor be preferred in catch
. And indeed Clang does so.
But GCC prefers copy constructor printing A(const A&)
. Demo: https://gcc.godbolt.org/z/1an5M7rWh
Even more weird thing happens in Visual Studio 2019 16.11.7, which prints nothing during program execution.
Which compiler is right here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
综上所述,clang和MSVC都是正确的。 GCC 调用了错误的构造函数。
有两个单独的对象
要理解所需的行为,我们必须了解在以下代码中,有两个对象:
首先, [ except.throw] p3 指出
其次 [except.handle] p14.2 解释,
GCC 调用了错误的构造函数
发生的情况类似于:
处理程序 中的变量为
const
的事实不会影响临时对象的 cv 限定,因为它们是两个独立的对象。临时对象不是
const
,因此在初始化期间A(A&)
是更好的匹配。海湾合作委员会是错误的。允许 MSVC 执行复制省略
此外,有可能执行复制省略。
该标准甚至在 [ except.throw] p7 中提供了一个示例:
[class.copy.elision] p1.4 确认它是允许,即使简历资格不匹配:
A
和省略const A
不是同一类型,但它们的区别仅在于简历资格,因此允许复制省略。In summary, clang and MSVC are both correct. GCC calls the wrong constructor.
There are two separate objects
To understand the required behavior, we must understand that in the following code, there are two objects:
Firstly, [except.throw] p3 states
Secondly [except.handle] p14.2 explains,
GCC calls the wrong constructor
What happens is similar to:
The fact that the variable in the handler is
const
doesn't affect the cv-qualifications of the temporary object because they are two separate objects.The temporary object is not
const
, soA(A&)
is a better match during initialization. GCC is wrong.MSVC is allowed to perform copy elision
Furthermore, it might possible that copy elision is performed.
The standard even has an example of that in [except.throw] p7:
[class.copy.elision] p1.4 confirms that it's allowed, even if cv-qualifications don't match:
A
andconst A
are not the same type, but they only differ in cv-qualification, so copy elision is allowed.