通用托管 C++陷阱

发布于 2024-11-15 04:05:11 字数 49 浏览 2 评论 0原文

在几乎完全使用非托管 C++ 后首次编写托管 C++ 时,需要注意哪些最常见的问题?

What are some of the most common issues to look out for when writing managed-C++ for the first time after almost exclusively working with unmanaged C++?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

薄荷梦 2024-11-22 04:05:11

当您使用内置 IJW(It Just Works)技术将托管委托转换为函数指针时,函数指针不保存对委托所属对象的引用。如果您不安排以其他方式保存引用,则可能会收集托管对象,然后当您调用该函数时,您将得到 NullReferenceException。

如果您正在创建一个需要回调的 C 库,并且希望将其包装在托管类中,那么您会经常遇到这种情况。托管类的客户端将提供一个委托,您可以将其转换为回调。您还必须保留对委托或目标对象的引用。

这在托管 C++ 和 C++/CLI 中是正确的。

When you convert a managed delegate to a pointer-to-function using the built-in IJW (It Just Works) technology, the pointer-to-function is not holding a reference to the object that the delegate was from. If you don't arrange to hold a reference some other way, the managed object may be collected, and then when you call the function, you'll get a NullReferenceException.

You run into this a lot if you are making a C-library that takes callbacks, and you want to wrap it in a Managed class. The client to the managed class will provide a delegate, which you convert to the callback. You must also keep a reference to the delegate or target object.

This is true in Managed C++ and C++/CLI.

初心未许 2024-11-22 04:05:11

如果您指的是 C++/CLI...

  • 通过引用传递参数时忘记使用 pin_ptr。与此相关的是,了解跟踪手柄和指针之间的区别至关重要。请参阅专家 C++/CLI 的第一章。
  • C++/CLI 没有 C# 的 yield 构造,我们在使用 Nunit 编写单元测试时经常使用它,使用 TestCaseSource 属性生成测试用例数据。这与下一篇有关。
  • 实现 System::IEnumerable 从语法上来说很麻烦。但一旦做了一次,就有了参考,所以也没有那么糟糕。
  • 了解析构函数和终结器之间的区别非常重要。有关此问题的讨论,请再次参阅 Expert C++/CLI 的第 4 章

If you mean C++/CLI...

  • Forgetting to use pin_ptr when passing arguments by reference. Related to this, it's vital to understand the difference between a tracking handle and a pointer. See the firsts chapters of Expert C++/CLI.
  • C++/CLI doesn't have C#'s yield construct, which we use a lot when writing Unit Tests with Nunit using the TestCaseSource attribute to generate test case data. This is related to the next one.
  • Implementing System::IEnumerable is sintactically cumbersome. But once you do it once, you have a reference, so it's not that bad.
  • It's very important to understand the difference between destructors and finalizers. For a discussion about this, again, see chapter 4 of Expert C++/CLI
待"谢繁草 2024-11-22 04:05:11

这是另一个问题:在对象上执行方法构成对该对象的引用。这意味着在执行成员方法期间,在您最后一次引用 this 之后,该对象可能会在该方法仍在执行时被清理,并且终结器可能会触发。

如果您的对象具有通过终结清除的任何非托管状态,或者包含具有此类非托管状态的任何其他对象,那么您正在对该非托管状态进行计算,请务必在 GC::KeepAlive 上调用 GC::KeepAlive在那些非托管计算之后的 code>this 。我现在倾向于将 GC::KeepAlive 附加到具有非托管计算的对象的所有方法。

Here's another gotcha: Executing a method on an object does not constitute a reference to the object. This means that during execution of a member method the object but after your last reference to this the object might be cleaned up while the method is still executing and the finalizer may fire.

If your object has any unmanaged state that is cleaned up by finalization or contains any other object with such unmanaged state are you're doing computations on that unmanaged state, be sure to call GC::KeepAlive on this after those unmanaged computations. I now tend to just append GC::KeepAlive to all methods of objects with unmanaged computation.

兮子 2024-11-22 04:05:11

一个陷阱(刚刚让我困惑):假设“析构函数只能执行一次”。由于析构函数是通过 Dispose 调用的,并且 Dispose 可能会被多次调用,因此这个假设(对于 C++ 来说没问题)不适用于 C++/CLI。

One gotcha (that just got me): assuming "the destructor can only be executed once". Since the destructor is invoked via Dispose, and Dispose might be called multiple times, this assumption (which is fine for C++) does not hold for C++/CLI.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文