在Visual Studio中缺少析构函数?

nit*_*nms 10 c++ destructor exception-handling visual-studio language-lawyer

我写了以下程序:

// 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我预期的输出是:

A ctor
A dtor
Internal exception caught
External exception caught
Run Code Online (Sandbox Code Playgroud)

这就是我在GCC中获得的.但是当我使用Visual Studio(2013版)时,我得到的输出是:

A ctor
External exception caught
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

Edg*_*jān 10

MSVC2013在这里是错误的,GCC是对的.不幸的是,我现在无法从标准中找到合适的参考,但是根据std :: uncaught_exception:

例如,如果堆栈展开导致堆栈分配的对象被破坏,则该对象的析构函数可以运行抛出异常的代码,只要在转义析构函数之前异常被某个catch块捕获.

有关更多详细信息,请参阅此处的"在堆栈展开期间进行投掷"部分.

最后,正如@StoryTeller所提到的,对于较新的MSVC版本,此行为不可重现.


我能找到的标准中最接近的匹配是下一个(来自N3936草案):

15.1抛出异常[except.throw]

  1. 如果异常处理机制在完成异常对象的初始化之后但在激活异常处理程序之前调用了一个通过异常退出的函数,则调用std :: terminate.

因此,正式地说,在堆栈展开过程(包括析构函数)中调用一个可能处理异常的函数是完全有效的,但是如果这个函数中的异常没有被适当的catch块捕获,那么std::terminate必须调用它.

  • [值得注意的是,MSVC2015的打印与GCC相同.这是100%的编译器错误.](http://rextester.com/live/BHLLV60541) (3认同)