为什么从类A的构造函数抛出的以下异常会被捕获两次,首先是构造函数本身内的catch,第二次是main函数中的catch?
为什么它不会被构造函数中的catch只捕获一次?
#include <iostream>
using namespace std;
class E {
public:
const char* error;
E(const char* arg) : error(arg) { }
};
class A {
public:
int i;
A() try : i(0) {
throw E("Exception thrown in A()");
}
catch (E& e) {
cout << e.error << endl;
}
};
int main() {
try {
A x;
}
catch(...)
{
cout << "Exception caught" << endl;
}
}
如果我删除main函数中的try-catch块,程序将崩溃。 这是输出:
Exception thrown in A()
terminate called after throwing an instance of 'E'
zsh: abort (core dumped) ./main
为什么没有主函数中的try-catch块会崩溃?
答案 0 :(得分:3)
构造函数中的函数try块无法阻止异常。一旦构造函数中发生异常,就没有对象,并且异常必须传播。 function-try-block唯一能做的就是进行局部清理。
构造函数确实是一个关于函数try-blocks的非常特殊的动物。
比照。 C ++ 11 15.3 / 14:
如果控件到达构造函数或析构函数的 function-try-block 的处理程序的末尾,则重新抛出当前处理的异常。
Tl; dr:永远不要使用function-try-blocks。
答案 1 :(得分:2)
似乎合乎逻辑。请考虑以下两种情况。
我。 Try块在构造函数体内:
A() : i(0) {
try
{
throw E("Exception thrown in A()");
}
catch (E& e) {
cout << e.error << endl;
}
// If code reaches here,
// it means the construction finished well
}
II。尝试块在初始化器中:
A() try : i(0) {
throw E("Exception thrown in A()");
}
catch (E& e) {
cout << e.error << endl;
// OK, you handled the exception,
// but wait you didn't construct the object!
}
在第一种情况下,在异常之后,您将在构造函数中处理它,然后您将正确构造该对象。
在第二种情况下,在异常之后你会在那里处理它。 但是你还没有构造对象,你在调用者身边没有任何对象。调用者应该处理未构造的对象情况。
答案 2 :(得分:2)
您正在使用名为function-try-catch的功能。在构造函数中使用时,它允许捕获初始化列表中的异常(对于捕获基类构造函数中的异常特别有用)以及构造函数体。但由于异常是在构造函数中抛出的,因此该类是不完整的,因此编译器会自动重新抛出任何捕获的异常。 这就是为什么你看到它被抓了两次。
阅读以下文章了解更多详情:
答案 3 :(得分:-1)
你在IDE工作吗?也许是你的调试器第一次捕获异常。您是否在输出中看到文字Exception thrown in A()
?我认为你最好通过const引用来捕获异常:
try {
throw E("Make a simpler test");
} catch (const E& e) {
cout << e.error << endl;
}