【问题标题】:Missing destructor in Visual Studio?Visual Studio 中缺少析构函数?
【发布时间】:2017-12-14 02:59:30
【问题描述】:

我写了以下程序:

// 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

这是怎么回事?

【问题讨论】:

  • “这是怎么回事?” - MS 编译器设计团队犯了一个错误:P

标签: c++ visual-studio exception-handling language-lawyer destructor


【解决方案1】:

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

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

有关更多详细信息,另请参阅“堆栈展开期间投掷” 部分 here

最后,正如@StoryTeller 所提到的,这种行为无法在较新的 MSVC 版本中重现。


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

15.1 抛出异常 [except.throw]

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

因此,正式地,在堆栈展开过程(包括析构函数)期间调用可能会处理异常的函数是完全有效的,但如果此类函数内的异常未被适当的catch 块捕获,则std::terminate 必须被调用。

【讨论】:

  • @Bathsheba 当堆栈展开期间从析构函数抛出异常时,我认为它是 UB,但是当它是 inside 析构函数时,它可能会在不调用 UB 的情况下被捕获。跨度>
  • @EdgarRokyan - 几乎正确。这只会调用std::terminate。所以不是未定义,只是从标准 POV 来看是灾难性的。
  • @StoryTeller 好点,一如既往!在这种情况下,std::terminate 将被调用。
  • @StoryTeller 至少现在已经修复了 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多