抛出例外时未执行(没有堆栈放松)的破坏者

Destructors not executed (no stack unwinding) when exception is thrown

本文关键字:堆栈 破坏者 执行      更新时间:2023-10-16

我发现了一个非常奇怪的行为,我从未见过。我正在研究一个复杂的VS2005 C 项目。

class Tester
{
public:
    Tester()
    {
        TRACE("Construct Tester");
    }
    ~Tester()
    {
        TRACE("~Destruct Tester");
    }
};
void Thrower()
{
    Tester X;
    throw std::exception("Booom");
}

当调用Thrower()时,您期望在跟踪输出中看到什么?该测试仪在堆栈被解开时被构造,然后破坏?

至少我期望这一点,但是测试仪的破坏者从未被称为!

不可能!?!?!?!

这是Visual Studio中的错误?

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

我花了整整一天的时间来找出出了什么问题。

现在,我必须更深入地解释自己在做什么。我有一个C 代码,该代码将其编译到LIB文件中。上面的代码(测试仪和投掷器)位于此普通的C LIB文件中。

我还有另一个C 代码,该代码将其编译到托管的C DLL中,该代码与此LIB文件链接在一起。因此,最后两个代码都在同一dll中。我管理了包装器功能,这些功能会在这样的LIB文件中调用代码:

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

这确实不工作。使用此代码,我有不关闭的内存泄漏和网络插座。投掷器中的堆栈没有解开。

这样做的原因是,在达到捕获之前不会发生堆栈。但是,当Catch坐在另一个图书馆中,而不是投掷堆栈就不会解开。DLL不知道如何在LIB文件中放松堆栈(尽管两者最终都被编译到同一DLL中!!)

,但我找到了一个非常简单的解决方案。

在lib文件中,我必须在theedwrapper()和类似的throter()之间添加一个中间功能。该代码看起来很愚蠢,但它解决了问题:

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

重要的是,该捕捉器必须坐在抛出异常的自由文件中。当捕获异常时,堆栈将解开,然后将异常重新插入托管包装器。

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

摘要:永远不要忘记,必须始终将异常捕获在它们被扔的同一库中。如果它们越过图书馆边界,您会有严重的问题。