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

phi*_*red 9 .net destructor c++-cli exception raii

我们有大量的本机C++代码,编译成DLL.

然后我们有几个包含C++/CLI代理代码的dll来包装C++接口.

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

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

但是我们有很多情况允许将原生C++异常传播到.Net世界,并且我们依赖.Net将这些包装为System.Exception对象的能力,并且在大多数情况下这很好.

但是,我们发现当异常传播时,不会调用throw的范围内对象的析构函数!

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

是否还有其他解决方法可以解决此问题 - 除了在(本机)try-catch-throw(除C++/CLI层之外)中包含跨本机管理边界的每个调用之外?

Jar*_*Par 3

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

正如您所指出的,最好的两个选择是

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

理想情况下,无论如何你都应该做第二个。根据我的经验,允许 C++ 异常跨越组件边界被认为是不好的做法。

您还可以使用_set_seh_translator文档)实现一个黑客解决方案。不过,我强烈建议避免使用该函数,因为它可能会无意中破坏 CLR 异常处理并导致许多不必要的问题。