gpt4 book ai didi

c++ - 抛出异常时不执行析构函数(不展开堆栈)

转载 作者:太空宇宙 更新时间:2023-11-04 11:41:16 25 4
gpt4 key购买 nike

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

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

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

调用 Thrower() 时,您希望在 Trace 输出中看到什么?是否构建了 Tester,然后在堆栈展开时销毁?

至少我希望如此,但是从未调用过 Tester 的析构函数!

不可能!?!?!?!

这是 Visual Studio 中的错误吗?

我进行了很多搜索,但甚至在 Stackoverflow 上也没有找到答案。

最佳答案

我花了一整天才找出问题所在。

现在我必须更深入地解释一下我在做什么。我有一个编译成 LIB 文件的 C++ 代码。上面的代码(Tester 和 Thrower)位于这个普通的 C++ LIB 文件中。

我还有另一个 C++ 代码,它编译成一个与这个 LIB 文件链接的托管 C++ DLL。所以最后两个代码都在同一个 DLL 中。我管理了调用 LIB 文件中代码的包装函数,如下所示:

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

有效。使用此代码,我有内存泄漏和未关闭的网络套接字。Thrower 中的堆栈未展开。

这是因为堆栈展开不会在到达 catch 之前发生。但是当 catch 位于另一个库中而不是 throw 时,堆栈不会展开。 DLL 不知道如何展开 LIB 文件中的堆栈(尽管两者最终都被编译成同一个 DLL!!)

但我找到了一个极其简单的解决方案。

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

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

重要的是这个捕捉器必须位于抛出异常的 LIB 文件中。当异常被捕获时,堆栈被展开,然后异常被重新抛出到托管包装器。

有时候看似愚蠢的代码其实很聪明!

总结:永远不要忘记必须始终在抛出异常的同一个库中捕获异常。如果它们越过图书馆边界被抓到,你就会遇到严重的问题。

关于c++ - 抛出异常时不执行析构函数(不展开堆栈),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21346400/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com