2014-01-25 37 views
1

我发现了一个非常非常奇怪的行为,我从未见过。 我正在处理一个复杂的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上找到答案。

回答

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()); 
    } 
} 

这确实工作。 使用此代码我有内存泄漏和未关闭的网络套接字。 Thrower中的堆栈未解开。

这样做的原因是在达到捕获之前不会发生堆叠展开。但是当抓住另一个图书馆而不是扔掉堆栈没有解开。 DLL不知道如何在LIB文件中展开堆栈(尽管两者最终都编译到同一个DLL中!!)

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

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

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

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

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

摘要:永远不要忘记,必须始终在引发异常的同一个库中捕获异常。如果他们跨越图书馆边界,则会遇到严重问题。

+0

如果这是Visual Studio中的一个错误,那么应该在互联网上有任何信息。但我找不到任何东西。但是,也许你是对的。 – Elmue

相关问题