抛出异常时,未执行的析构函数(无堆栈展开) [英] Destructors not executed (no stack unwinding) when exception is thrown

查看:158
本文介绍了抛出异常时,未执行的析构函数(无堆栈展开)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现了一个非常非常奇怪的行为,我从来没有见过。
我正在处理一个复杂的VS2005 C ++项目。

I found a very very weird behaviour that I have never seen before. I'm working on a complex VS2005 C++ project.

class Tester
{
public:
    Tester()
    {
        TRACE("Construct Tester");
    }
    ~Tester()
    {
        TRACE("~Destruct Tester");
    }
};

void Thrower()
{
    Tester X;
    throw std::exception("Booom");
}

Thrower()被调用?
那个测试器被构造,然后在堆栈解开时被破坏,或者不是?

What do you expect to see in Trace output when Thrower() is called? That Tester is constructed and then destructed when the stack is unwinded, or not?

至少我期望这样,但是Tester的析构函数从不被调用!

At least I expect that, but the destructor of Tester is never called!

不可能!?!?!?!

这是Visual Studio中的错误吗?

Is this a bug in Visual Studio ?

我搜索了很多,但是在Stackoverflow甚至没有找到答案。

I searched a lot but not even on Stackoverflow I found an answer.

推荐答案

我花了一整天的时间找出错误的原因。

It took me an entire day to find out what was wrong.

现在我要更详细地解释一下我在做什么。
我有一个C ++代码编译成一个LIB文件。上面的代码(Tester和Thrower)位于这个简单的C + + LIB文件中。

Now I have to explain a little deeper what I'm doing. I have a C++ code that compiles into a LIB file. The code above (Tester and Thrower) sits in this plain C++ LIB file.

我有另一个C ++代码编译成一个Managed C ++ DLL, 。所以最后两个代码都在同一个DLL中。我已经管理包装函数调用LIB文件中的代码如下:

And I have another C++ code that compiles into a Managed C++ DLL which links with this LIB file. So at the end both codes are in the same DLL. I have managed wrapper functions that call the code in the LIB file like this:

ManagedWrapper()
{
    try
    {
        Thrower();
    }
    catch (std::exception& e)
    {
        throw new System::Exception(e.what());
    }
}

这会
使用这个代码我有内存泄漏和网络套接字没有关闭。
Thrower中的堆栈没有解开。

This does NOT work. With this code I have memory leaks and network sockets that are not closed. The stack in Thrower is not unwound.

这样做的原因是堆栈展开不会在达到catch之前发生。但是当catch坐在另一个库而不是throw堆栈不解开。 DLL不知道如何解开LIB文件中的堆栈(尽管这两个文件最终编译到同一个DLL中)

The reason for this is that stack unwinding does not take place before catch is reached. But when catch sits in another library than throw the stack is not unwound. The DLL does not know how to unwind the stack in the LIB file (although both are finally compiled into the same DLL!!)

但是我发现了一个非常简单的解决方案。

But I found an extremely simple solution.

在LIB文件中,我不得不像这样在ManagedWrapper()和Thrower()之间添加一个中间函数。代码看起来很愚蠢,但它解决了问题:

In the LIB file I had to add an intermediate function between the ManagedWrapper() and the Thrower() like this. The code looks stupid, but it solves the problem:

Catcher()
{
    try
    {
         Thrower();
    }
    catch(...) // unwind HERE
    {
        throw;
    }
}

重要的是这个捕手必须坐在LIB文件,其中抛出异常。当异常被捕获时,堆栈被解开,然后异常被重新抛出到托管包装器。

The important thing is that this catcher must sit in the LIB file where the exception is thrown. When the exception is catched, the stack is unwound and then the exception is re-thrown to the managed wrapper.

有时看起来愚蠢的代码是非常聪明的!

Sometimes code that looks stupid is very intelligent!

SUMMARY :永远不要忘记异常必须始终在它们被抛出的同一个库中。如果他们跨越图书馆边界,你有严重的问题。

SUMMARY: Never forget that exception must always be catched in the same library where they have been thrown. If they are catched across a library boundary you have severe problems.

这篇关于抛出异常时,未执行的析构函数(无堆栈展开)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆