为什么异常时不调用析构函数?

发布于 2024-07-08 08:32:52 字数 546 浏览 8 评论 0原文

我期望在此程序中调用 A::~A() ,但事实并非如此:

#include <iostream>

struct A {
  ~A() { std::cout << "~A()" << std::endl; }
};

void f() {
  A a;
  throw "spam";
}

int main() { f(); }

但是,如果我将最后一行更改为

int main() try { f(); } catch (...) { throw; }

A::~A() code>被调用

我正在使用 Visual Studio 2005 中的“Microsoft (R) 32 位 C/C++ 优化编译器版本 14.00.50727.762 for 80x86”进行编译。命令行为 cl /EHa my.cpp

编译器正常吗? 标准对这个问题有何规定?

I expected A::~A() to be called in this program, but it isn't:

#include <iostream>

struct A {
  ~A() { std::cout << "~A()" << std::endl; }
};

void f() {
  A a;
  throw "spam";
}

int main() { f(); }

However, if I change last line to

int main() try { f(); } catch (...) { throw; }

then A::~A() is called.

I am compiling with "Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86" from Visual Studio 2005. Command line is cl /EHa my.cpp.

Is compiler right as usual? What does standard say on this matter?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

や三分注定 2024-07-15 08:32:52

未调用析构函数,因为在堆栈展开之前调用了未处理异常的终止()。

C++ 规范所说的具体细节超出了我的知识范围,但使用 gdb 和 g++ 进行的调试跟踪似乎证实了这一点。

根据标准草案第 15.3 条第 9 条:

9 If no matching handler is found in a program, the function terminate()
  (_except.terminate_)  is  called.  Whether or not the stack is unwound
  before calling terminate() is implementation-defined.

The destructor is not being called because terminate() for the unhandled exception is called before the stack gets unwound.

The specific details of what the C++ spec says is outside of my knowledge, but a debug trace with gdb and g++ seems to bear this out.

According to the draft standard section 15.3 bullet 9:

9 If no matching handler is found in a program, the function terminate()
  (_except.terminate_)  is  called.  Whether or not the stack is unwound
  before calling terminate() is implementation-defined.
缪败 2024-07-15 08:32:52

C++语言规范指出:
为从 try 块到 throw 表达式的路径上构造的自动对象调用析构函数的过程称为“堆栈展开”。
您的原始代码不包含 try 块,这就是堆栈展开不会发生的原因。

C++ language specification states:
The process of calling destructors for automatic objects constructed on the path from a try block to a throw-expression is called “stack unwinding.”
Your original code does not contain try block, that is why stack unwinding does not happen.

—━☆沉默づ 2024-07-15 08:32:52

抱歉,我身上没有该标准的副本。
我肯定想对此有一个明确的答案,因此拥有标准副本的人希望分享有关正在发生的事情的章节:

根据我的理解,终止仅被称为 iff:

  • 异常处理机制无法找到引发异常的处理程序。< br>
    以下是更具体的案例:

    • 在堆栈展开期间,异常会从析构函数中逃脱。
    • 抛出的表达式,异常会从构造函数中转义。
    • 异常会转义非局部静态(即全局)的构造函数/析构函数
    • 异常会转义使用 atexit() 注册的函数。
    • 异常逃逸 main()
  • 当前没有异常正在传播时尝试重新抛出异常。
  • 意外异常使用异常说明符转义函数(通过意外)

Sorry I don't have a copy of the standard on me.
I would definitely like a definitive answer to this, so somebody with copy of the standard want to share chapter and verse on whats happening:

From my understanding terminate is only called iff:

  • The exception handling mechanism cannot find a handler for a thrown exception.
    The following are more specific cases of this:

    • During stack unwinding, an exception escapes a destructor.
    • An thrown expression, an exception escapes the constructor.
    • An exception escapes the constructor/destructor of a non local static (ie global)
    • An exception escapes a function registered with atexit().
    • An exception escapes main()
  • Trying to re-throw an exception when no exception is currently propagating.
  • An unexpected exception escapes a function with exception specifiers (via unexpected)
审判长 2024-07-15 08:32:52

在第二个示例中,dtor 在离开 try{} 块时被调用。

在第一个示例中,当程序离开 main() 函数后关闭时,将调用 dtor——此时 cout 可能已经被销毁。

In the second example, the dtor is called when it leaves the try{} block.

In the first example, the dtor is called as the program shuts down after leaving the main() function --- by which time cout may already have been destroyed.

泪之魂 2024-07-15 08:32:52

我还假设编译器不会生成相对于“a”的代码,因为它没有被引用,但这仍然不是正确的行为,因为析构函数做了一些必须执行的事情。

所以,我在 VS2008/vc9 (+SP1) 中尝试过,调试和发布,并且在引发异常后调用 ~A,退出 f() - 如果我是对的,这是正确的行为。

现在我刚刚尝试使用 VS2005/vc8 (+SP1),它的行为是相同的。

我使用断点来确定。 我刚刚检查了控制台,我也收到了“~A”消息。 也许你在其他地方做错了?

I assumed too that the compiler don't generate the code relative to "a" as it's not referenced but still, it's not the right behavior as the destructor does something that have to be executed.

So, i tried in VS2008/vc9 (+SP1), Debug and Release and ~A is called after the exception is thrown, getting out of f() - that is the right behavior, if i'm right.

Now i just tried with VS2005/vc8 (+SP1) and it's the same behavior.

I used breakpoints to be sure. I just checked with the console and i have the "~A" message too. Maybe you did it wrong somewhere else?

三生殊途 2024-07-15 08:32:52

这个问题很容易谷歌,所以我在这里分享我的情况。

确保您的异常不会跨越 extern "C" 边界或使用 MSVC 选项 /EHs(启用 C++ 异常 = 使用 Extern C 函数 (/EHs) 是)

This question is easy to google so I share my situation here.

Make sure yor exeption does not cross extern "C" boundary or use MSVC option /EHs (Enable C++ exeptions = Yes with Extern C functions (/EHs))

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文