Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 当本机(C+;+;)异常传播到CLR组件时未调用析构函数 我们有大量的本地C++代码,编译成DLL。 我们有两个包含C++和CLI代理代码的DLL来封装C++接口。_.net_Exception_C++ Cli_Destructor_Raii - Fatal编程技术网

.net 当本机(C+;+;)异常传播到CLR组件时未调用析构函数 我们有大量的本地C++代码,编译成DLL。 我们有两个包含C++和CLI代理代码的DLL来封装C++接口。

.net 当本机(C+;+;)异常传播到CLR组件时未调用析构函数 我们有大量的本地C++代码,编译成DLL。 我们有两个包含C++和CLI代理代码的DLL来封装C++接口。,.net,exception,c++-cli,destructor,raii,.net,Exception,C++ Cli,Destructor,Raii,除此之外,我们还将C#代码调用到C++/CLI包装器中 到目前为止,都是些标准的东西 但是我们有很多的例子,其中允许本地C++异常传播到.NET世界,我们依赖.NET的能力来封装这些Syt.Exchange对象,并且大多数情况下都很好。 然而,我们发现,当异常传播时,抛出点作用域中对象的析构函数没有被调用 经过一些研究,我们发现这是一个相当众所周知的问题。然而,解决方案/变通办法似乎不太一致。我们确实发现,如果使用/EHa而不是/EHsc编译本机代码,问题就会消失(至少在我们的测试用例中是这样)

除此之外,我们还将C#代码调用到C++/CLI包装器中

到目前为止,都是些标准的东西

但是我们有很多的例子,其中允许本地C++异常传播到.NET世界,我们依赖.NET的能力来封装这些Syt.Exchange对象,并且大多数情况下都很好。 然而,我们发现,当异常传播时,抛出点作用域中对象的析构函数没有被调用

经过一些研究,我们发现这是一个相当众所周知的问题。然而,解决方案/变通办法似乎不太一致。我们确实发现,如果使用/EHa而不是/EHsc编译本机代码,问题就会消失(至少在我们的测试用例中是这样)。然而,我们更喜欢使用/eHSC,因为我们自己将SEH异常转换成C++异常,而我们宁愿让编译器有更多的优化范围。
这个问题还有其他解决方法吗?除了在(本机)try-catch抛出中(除了C++/CLI层之外)包装每个跨本机托管边界的调用之外?

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

  • 使用/EHa编译
  • 在函数的入口点和出口点添加try/catch
理想情况下,你无论如何都应该做第二件事。根据我的经验,允许C++异常跨越组件边界是一种错误的做法。
使用
\u set\u seh\u translator
()也可能会有一个黑客解决方案。但是,我强烈建议避免使用该函数,因为它可能会无意中破坏CLR异常处理,并导致许多不必要的问题

我认为你做得不对。使用_set_se_translator()已经要求您使用/EHa进行编译。从:

更严重的是,在使用托管代码时,您会破坏它。CLR依靠SEH异常来检测各种事故。它使用SetUnhandledExceptionFilter来捕获它们。特别是NullReferenceException和OverflowException(x86)是以这种方式提出的。当您注入自己的uuu try块时,您将阻止此异常流入CLR。尽管您将“处理”它,但您不会有任何关于异常的确切原因的线索。托管的try/catch块无法检测到它


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

用于/E编译器开关的MSDN页面确实说明了此行为:-

以下是相关报价:-

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

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

如果您可以保证永远不会导致访问冲突、页内错误或其他SEH,那么请使用/EHsc。但是,如果您正在编写服务和/或希望提供“尽最大努力”,那么/EHa将是必要的


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

CLR的2.0版本中有一个错误导致了此问题。在4.0 CLR上运行托管可执行文件将允许按预期调用析构函数


有关详细信息,请参阅。

我们实际上自己也在使用SetUnhandledExceptionFilter()。我们确实链接到大量注册的过滤器上,因此如果在围栏的.Net一侧有一个处理程序仍然可以查看(这就是在提示问题的情况下发生的情况)。使用64位代码对我们来说不是一个选项,因为这是一个必须能够在台式机上运行的框架(我们当前的标准是XP)。谢谢Chris。然而,我的问题是C++异常。至于跨越模块边界,我将对@JaredPar的回答进行评论。很抱歉,我把重点放在了/EHa上。你是说即使是正常的投掷你也能看到吗?e、 g.抛出std::runtime_error();我们实际上使用的是SetUnhandledExceptionFilter()(请参阅我对@nobugz的响应),并且在处理过程中考虑了CLR异常。对于跨越组件边界的C++异常:(1)承诺是由运行时自动为我们处理的,而不是这个问题,它是。(2) 如果我们要这样做,那么逻辑位置将在我们的C++/CLI代理代码中。但因为这已经是CLI代码了,所以现在发现这个问题已经太迟了。因此,要沿着这条路线走下去,我们实际上必须有两层包装(一层是本地的,一层是托管的)!你找到正确的答案了吗?很遗憾,我现在不记得了
You must use /EHa when using _set_se_translator.