struct test { test() { if (!id) throw this; } int *id = nullptr; }; struct testex : public test { testex() try :test() { } catch (test *t) { (*t).id = new int(1); } }; int main() { testex t; return 0; }
求帮忙解释一下,以上代码为何在正确捕获异常后又产生了一个异常?
这个问题比想象中的要深,也是我第一次看到这样的try用法,如果回答有错还请高人指正。
我运行后的异常消息是:
Exception thrown at 0x765CB802 in ConsoleApplication1.exe: Microsoft C++ exception: test at memory location 0x001DF850. (这个是你抛出的异常)
Exception thrown at 0x765CB802 in ConsoleApplication1.exe: Microsoft C++ exception: [rethrow] at memory location 0x00000000. (异常在你catch上个异常后,被重新抛出来了,异常原因是访问0地址)
Unhandled exception at 0x765CB802 in ConsoleApplication1.exe: Microsoft C++ exception: test at memory location 0x001DF850. (你没有catch那个被重新抛出来的异常,最后崩溃掉了。)
0x00000000异常的原因应该是父类构造的失败造成导致了`testex`构造的失败,然后这个异常没有被处理,最终导致崩溃。
int main() { try { testex t; } catch (testex *t) { std::cout << "testex exception" << std::endl; } catch (test *t) { std::cout << "test exception" << std::endl; } return 0; }
赞成你的说法,但是还有个疑问,我改写main函数如上,但是发现第二次捕获的异常是test而不是testex,
按道理说应该抛出一个testex类型的异常才对。
在你代码里面,是永远不会有类型为testex*的异常的,因为你只有一个显式的throw,其类型为test*。
因为构造的失败,你在`test`构造的异常被重新抛出了,然后这个重新抛出异常被你外围的`catch (test *t)`捕捉到了。
@asahi86: 我又做了几个实验,确实是重新抛出了我显示的throw, 这有点让我怀疑这种try用法是否实用,从这个例子看,无论在构造函数里怎么catch,都会重新抛出异常,而且只有在最外层调用的时候catch才能避免这个问题。
是什么异常,把你的异常截图上来看看。
构造函数一样,一般实践是要避免的 Effective C++系列等都有讲解具体的原因
(*t).id = new int(1); 第二次异常,估计是*t是个空,所以其id无法取到
在catch的时候,t作为异常消息还没有被销毁,就算没有做catch里面的逻辑仍然会有一样的二次异常。
@asahi86: 不对id做处理的时候也会有异常,所以应该不是*t是空的问题,但是t作为异常对象是一个指针,应该不会销毁t指的对象,而是对t这个指针做了个拷贝,结束后销毁了这个指针,但这样也不应该会产生异常。