代码之家  ›  专栏  ›  技术社区  ›  philsquared

当本机(C++)异常传播到CLR组件时不调用析构函数

  •  9
  • philsquared  · 技术社区  · 15 年前

    我们有大量的本地C++代码,并被编译成DLL。

    最重要的是,我们有C++代码调用到C++ /CLI包装器中。

    标准的东西,到目前为止。

    然而,我们发现当异常传播时,在抛出点的作用域中的对象的析构函数没有被调用!

    经过研究,我们发现这是一个众所周知的问题。然而,解决方案/解决方法似乎不太一致。我们确实发现,如果使用/EHa而不是/EHsc编译本机代码,问题就会消失(至少在我们的测试用例中是这样)。然而,我们更喜欢使用/EHSC,因为我们自己翻译SEH异常到C++异常,我们宁愿让编译器有更多的优化范围。

    除了这个(本地)尝试catch抛出(除了C++ + CLI层)之外,还有其他的解决方案吗?

    4 回复  |  直到 15 年前
        1
  •  3
  •   JaredPar    15 年前

    不幸的是没有我不相信有任何好的解决办法。MS平台上的C++异常实现是使用SEH异常(IIRC)实现的。CLR挂接到SEH处理中,以捕获本机异常并将其处理为CLR异常。因为它在SEH级别捕获它们,所以异常看起来像C++的SEH异常,并且析构函数运行或不运行。

    正如你所说,最好的两个选择是

    • 用/EHa编译
    • 在函数的入口和出口添加try/catch

    理想情况下,你应该做第二个无论如何。根据我的经验,允许C++异常跨越组件边界是一种错误的做法。

    也有可能是一个黑客的解决方案,你可以实现使用 _set_seh_translator ( Documentation

        2
  •  3
  •   Hans Passant    15 年前

    我认为你做得不对。使用\u set \u se \u translator()已经要求您使用/EHa进行编译。从 MSDN Library page

    You must use /EHa when using _set_se_translator.
    

    解决/EHa效率(如果它实际上是一个问题)的方法是64位代码。它基于函数表的堆栈展开非常有效,try块的开销为零。

        3
  •  3
  •   Chris Oldwood    15 年前

    /E compiler开关的MSDN页没有说明这一点behaviour:-

    http://msdn.microsoft.com/en-us/library/1deeycx5(VS.80).aspx

    如果您使用/EHs,那么您的捕获 子句将不捕获异步 例外情况。此外,在Visual C++ 2005中, 当 即使 已处理异步异常。

    基本上,EHSC是乐观的观点——它假定唯一的例外是真正的C++风格的,并将相应地优化。另一方面,EHa持悲观的观点,认为任何一行代码都可能导致生成异常。

    我也同意@JaredPar关于不允许异常跨越模块边界的观点。Nobgz说CLR处理异常的方式可能是正确的,但是我认为.NET代码直接调用本地代码使用P/Unjk和调用C++ + CLI互操作DLL有区别。在前一种情况下,CLR必须代表您处理情况,而在后一种情况下,您可以控制并相应地进行翻译。

        4
  •  1
  •   Community CDub    7 年前