我发现了一个非常奇怪的行为,我从未见过。我正在研究一个复杂的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;
}
}
重要的是,该捕捉器必须坐在抛出异常的自由文件中。当捕获异常时,堆栈将解开,然后将异常重新插入托管包装器。
有时看起来很愚蠢的代码非常聪明!
摘要:永远不要忘记,必须始终将异常捕获在它们被扔的同一库中。如果它们越过图书馆边界,您会有严重的问题。