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

2023-09-03 11:17:04 作者:凉心.

我们有一个庞大的身躯本地C ++的code,compliled成的DLL。

然后,我们有一对夫妇含C ++ / CLI代理code包的C ++接口的DLL。

在最重要的是,我们有C#code调用到C ++ / CLI包装。

标准的东西,这么远。

但我们有很多,其中本地C ++异常被允许传播到.NET世界的情况下,我们依靠的.Net的把它们包装为System.Exception的对象的能力,并在大多数情况下能正常工作。

不过,我们已经发现,在抛出点的范围对象的析构函数,当异常传播不被调用!

经过一番研究,我们发现,这是一个相当著名的问题。然而,解决方案/解决方法似乎不太一致。我们也发现,如果本机code编译时/ EHA而不是/ EHSC问题消失(至少在我们的测试情况下,它所做的那样)。不过,我们更希望将preFER使用/ EHSC为我们翻​​译SEH例外C ++异常我们自己和我们宁愿让优化编译器更多的余地。

还有没有其他的解决方法这个问题 - 不是包装在整个本地管理边界每个呼叫之外的(本地)的try-catch掷(除C ++ / CLI层)

解决方案

在MSDN页面/ E编译器开关状态,是否这种行为: -

c 语言介绍

http://msdn.microsoft.com/ EN-US /库/ 1deeycx5(VS.80)的.aspx

下面是相关报价: -

  

如果您使用/ EHS,那么你的抓   条款不会赶上异步   异常。此外,在Visual C ++ 2005,   在范围当所有对象   产生异步异常   将不被即使被破坏的   异步异常被处理。

基本上/ EHSC是乐观的观点 - 它假定唯一的例外是真正的C ++风格的人,并会相应地优化。 / EHA,另一方面采取了悲观的看法,并假定的code的任何行可能导致产生异常。

如果你能机制保障,你永远也不会造成访问冲突,或在页错误或其他SEH然后使用/ EHSC。但是,如果你正在写一个服务和/或想提供一个尽力而为,那么/ EHA将是必要的。

我也同意@ JaredPar的情绪有关不允许例外跨越模块边界。什么@nobugz说,大约在CLR处理的异常可能是真实的方式,但我认为这是C调用出来,直接到本机code使用P / Invoke,并呼吁为C ++ / CLI互操作的净$ C $的差异DLL。在前者的情况下在CLR必须处理的情况代表你的,而在后者你在控制和可以相应翻译

We have a large body of native C++ code, compliled into DLLs.

Then we have a couple of dlls containing C++/CLI proxy code to wrap the C++ interfaces.

On top of that we have C# code calling into the C++/CLI wrappers.

Standard stuff, so far.

But we have a lot of cases where native C++ exceptions are allowed to propagate to the .Net world and we rely on .Net's ability to wrap these as System.Exception objects and for the most part this works fine.

However we have been finding that destructors of objects in scope at the point of the throw are not being invoked when the exception propagates!

After some research we found that this is a fairly well known issue. However the solutions/ workarounds seem less consistent. We did find that if the native code is compiled with /EHa instead of /EHsc the issue disappears (at least in our test case it did). However we would much prefer to use /EHsc as we translate SEH exceptions to C++ exceptions ourselves and we would rather allow the compiler more scope for optimisation.

Are there any other workarounds for this issue - other than wrapping every call across the native-managed boundary in a (native) try-catch-throw (in addition to the C++/CLI layer)?

解决方案

The MSDN page for the /E compiler switch does state this behaviour:-

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

Here is the relevant quote:-

If you use /EHs, then your catch clause will not catch asynchronous exceptions. Also, in Visual C++ 2005, all objects in scope when the asynchronous exception is generated will not be destroyed even if the asynchronous exception is handled.

Basically /EHsc is the optimistic view - it assumes that the only exceptions are true C++ style ones and will optimise accordingly. /EHa on the other hand takes the pessimistic view and assumes that any line of code could cause an exception to be generated.

If you can guarentee that you'll never cause an Access Violation, or In-Page Error or other SEH then use /EHsc. But If you're writing a service and/or want to provide a "best effort" then /EHa is going to be necessary.

I also agree with @JaredPar's sentiments about not allowing exceptions to cross module boundaries. What @nobugz says about the way the CLR handles exceptions may be true, but I think there is a difference between .Net code calling out directly to native code using P/Invoke and calling into a C++/CLI interop DLL. In the former case the CLR has to handle the situation on your behalf, whereas in the latter you are in control and can translate accordingly.