我写了以下程序:
// Example program
#include <iostream>
#include <string>
#include <exception>
struct A {
A() {
std::cout << "A ctor" << std::endl;
}
~A() {
std::cout << "A dtor" << std::endl;
try {
throw std::exception();
} catch (std::exception &e) {
std::cout << "Internal exception caught" << std::endl;
}
}
};
int main()
{
try {
A a;
throw std::exception();
} catch (std::exception &e) {
std::cout << "External exception caught" << std::endl;
}
}
我预期的输出是:
A ctor
A dtor
Internal exception caught
External exception caught
这就是我在GCC中获得的。但是,当我使用Visual Studio(2013版)时,我得到的输出是:
A ctor
External exception caught
这里发生了什么?
答案 0 :(得分:10)
MSVC2013 在这里是错误的, GCC 是对的。不幸的是,我现在无法从标准中找到合适的参考,但根据std::uncaught_exception:
例如,如果堆栈展开导致堆栈分配的对象 destructed,该对象的析构函数可以运行抛出的代码 只要异常被某个catch块捕获就会出现异常 在逃避析构函数之前。
有关详细信息,另请参阅“在堆栈展开期间投掷”部分here。
最后,正如@StoryTeller所提到的,对于较新的MSVC版本,此行为无法重现。
我能找到的最接近的标准是下一个(来自N3936草案):
15.1抛出异常[except.throw]
- 如果是异常处理机制,完成后 初始化异常对象但在激活之前 异常的处理程序,调用通过一个退出的函数 异常,调用std :: terminate。
醇>
因此,正式地说,在堆栈展开过程(包括析构函数)中调用一个可能处理异常的函数是完全有效的,但是如果这个函数中的异常没有被适当的catch
块捕获那么{{必须要调用1}}。