C++ 使用函数try块的构造函数会引发两次异常
为什么从类A的构造函数抛出的以下异常会被捕获两次,第一次是由构造函数本身中的捕获,第二次是由主函数中的捕获 为什么它不被构造函数中的捕获捕获一次呢C++ 使用函数try块的构造函数会引发两次异常,c++,exception,exception-handling,constructor,try-catch,C++,Exception,Exception Handling,Constructor,Try Catch,为什么从类A的构造函数抛出的以下异常会被捕获两次,第一次是由构造函数本身中的捕获,第二次是由主函数中的捕获 为什么它不被构造函数中的捕获捕获一次呢 #include <iostream> using namespace std; class E { public: const char* error; E(const char* arg) : error(arg) { } }; class A
#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;
}
}
为什么它在主函数中没有try-catch块的情况下崩溃?构造函数中的函数try块无法防止异常。一旦构造函数中发生异常,就没有对象,异常必须传播。函数try块只能做一些局部清理 对于函数try块,构造函数确实是一种非常特殊的动物 参见C++11 15.3/14: 如果控件到达构造函数或析构函数的函数try块的处理程序末尾,则当前处理的异常将被重试
Tl;dr:永远不要使用函数try块。这似乎合乎逻辑。考虑以下两种情况: 一,。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
}
A():i(0){
尝试
{
抛出E(“在A()中抛出异常”);
}
捕获(E&E){
cout您正在使用一个名为的功能。当在构造函数中使用时,它允许捕获初始化列表中的异常(特别适用于捕获基类构造函数中的异常)但是由于异常是在构造函数中抛出的,因此类是不完整的,因此编译器会自动重新引用捕获到的任何异常。
这就是为什么你看到它被抓了两次
有关更多详细信息,请阅读以下文章:
另外,如果将try
放在构造函数的主体中,您将捕获一个异常。@MM.是的,这是为什么?如果没有主函数中的try-catch块,它将不再崩溃。请不要捕获省略号…正确操作并捕获相应的异常。您最好使用const
引用捕获异常。因为您通常不想在抛出/捕获后更改它们,如果您需要创建一个新副本并重新生成此副本。那么这是否意味着虽然已执行捕获块,但它捕获但随后失败?但为什么在构造函数中使用try-catch捕获一次?函数try-blocks和try-catc之间有什么区别函数中的h块?@takwing:是的。初始化过程中引发的异常意味着对象无法正确构造,因此不应该存在。如果在外部捕捉到异常,则可以处理对象构造失败的事实。如果在构造函数主体内捕捉到异常,则它将不会是异常这源于初始化,但源于成功构造后执行的某个语句。@takwing:作用域不同。函数体作用域内有一个普通的try/catch块。函数体作用域周围有一个函数try块。@KerrekSB:顺便问一句,如果有的话,什么是真正的有趣用例tion try block?@M,调用方捕获的第二个异常是否与构造函数抛出的第一个异常不同?根据您的解释,第二个异常应该是异常,因为对象的构造不完整,对吗?@takwing:不,它们是相同的。是的。事实上,第二个场景将是在异常中划行。
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
}
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!
}