我发现了一种我从未见过的非常奇怪的行为。 我正在开发一个复杂的VS2005 C ++项目。
class Tester
{
public:
Tester()
{
TRACE("Construct Tester");
}
~Tester()
{
TRACE("~Destruct Tester");
}
};
void Thrower()
{
Tester X;
throw std::exception("Booom");
}
调用Thrower()
时,您希望在跟踪输出中看到什么?
构建测试器然后在堆栈展开时被破坏吗?
至少我希望如此,但Tester的析构函数从未被调用过!
不可能!?!?!?!
这是Visual Studio中的错误吗?
我搜索了很多但是甚至没有在Stackoverflow上我找到了答案。
答案 0 :(得分:1)
我花了一整天的时间来找出问题所在。
现在我必须更深入地解释一下我在做什么。 我有一个编译成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());
}
}
NOT 工作。 使用此代码,我有内存泄漏和未关闭的网络套接字。 Thrower中的堆栈没有解开。
原因是在达到catch之前不会发生堆栈展开。但是当catch位于另一个库而不是抛出时,堆栈并未解开。 DLL不知道如何在LIB文件中展开堆栈(尽管两者最终都被编译到同一个DLL中!)
但我找到了一个非常简单的解决方案。
在LIB文件中,我必须在ManagedWrapper()和Thrower()之间添加一个中间函数。代码看起来很愚蠢,但它解决了这个问题:
Catcher()
{
try
{
Thrower();
}
catch(...) // unwind HERE
{
throw;
}
}
重要的是,此捕获器必须位于引发异常的LIB文件中。当捕获到异常时,堆栈被展开,然后异常被重新抛出到托管包装器。
有时看起来很愚蠢的代码非常聪明!
摘要:永远不要忘记必须始终在引发它们的同一个库中捕获该异常。如果它们跨越图书馆边界,则会出现严重问题。