【问题标题】:Destruct Unmanaged object From .NET code从 .NET 代码中销毁非托管对象
【发布时间】:2011-09-27 20:22:02
【问题描述】:

我编写了一个 C++ 库,它通过 C++/CLI 包装器向我的 VB.NET 应用程序公开。

我担心通过包装器传送到 VB.NET 应用程序的对象。为了使用库中的类,我为它们编写了包装器,并且包装器类包含指向该类的非托管实例的指针。在包装类的析构函数中,我删除了非托管指针指向的内存。

如果包装的 .NET 库将这些类实例之一传递给 VB.NET 应用程序并且 VB.NET 应用程序使用它并继续前进(不保存对它的引用); .NET 垃圾收集器会出现并处理此类实例,从而导致在类的析构函数中释放非托管内存吗?如果我引用了包装类实例指向的同一内存,这将导致错误。

如果是这种情况,那么我将复制包装器中的所有数据,以确保我的包装器不会与库的本机部分共享任何数据。如果不是这种情况,那么我是否必须在包装的类实例上调用某种 dispose 方法才能破坏非托管对象?

【问题讨论】:

    标签: .net c++-cli unmanaged managed


    【解决方案1】:

    在 CLI 中,您只需使用析构函数语法 (~MyClass()),C++/CLI 编译器就会为您在类上创建一个 IDisposable 实现。

    当在非托管代码中调用Dispose method 时,将调用这个“析构函数”(它不是真的,它只是语法)。您可以在这里进行调用以释放资源。

    如果您想实现终结器,那么您将使用新的析构函数语法 (!MyClass())。这应该会释放与“析构函数”中相同的资源。

    最后,在您的托管代码中,您只需引用IDisposable 实现,然后对其调用Dispose,很可能通过using statement

    【讨论】:

    • 如果我同时声明析构函数 (~MyClass()) 和终结器 (!MyClass()) 并在我的 c++/cli 包装器中实现它们,我想我可能会有点混淆,然后在我将它们转换为 IDisposable 之后,我将自动能够对这些对象调用 dispose。我想我听说调用 dispose 可能很危险,或者那可能是在调用垃圾收集器,我不记得了。
    • @Ian:调用Dispose 确实调用垃圾收集器。这是完全错误的。析构函数 (~) 用于 IDisposable 实现,而终结器 (!) 用于终结器(如果计划用于终结,则会被垃圾收集器调用)。一般来说,如果您的 CLI 类中有非托管资源,您应该实现 IDisposable(显然,~ 非常容易)以便您的托管调用者可以尽快处理非托管资源。
    【解决方案2】:

    你有点混淆了。是的,在 vb.net 代码停止引用您的 C++/CLI 类之一之后,最终将在对象被收集后调用终结器。请注意,这是 finalizer,它与 dispose 无关。您的 C++/CLI 对象应同时提供析构函数(由 Dispose() 调用)和终结器。

    否则没有内存损坏的危险。只有当垃圾收集器找不到对该对象的任何实时引用时,才会调用终结器。由于没有留下任何引用,因此您不可能意外访问已删除的本机对象。检查this answer 的标准模式。

    【讨论】:

    • 好吧,如果我在库中有一个仍然引用该内存的本机指针,那么垃圾收集器可能(间接地)处理它并且我在库中的非托管引用会导致错误,对吧?我猜垃圾收集器不会检查 c++/cli 类中的非托管指针,看看它们是否指向指向其他地方的内存。
    • 不,这取决于你。比如说,使用 shared_ptr。您所知道的是托管代码将永远不会再次使用它。如果托管代码无法对它做任何事情,请考虑保持该对象活动是否仍然有意义。我不知道这是否相关。
    • 好的,谢谢。就我而言,它确实有意义,因为库有一个持久的对象列表,但有时这些对象会传递给 .NET 应用程序。我只需要确保我进行了数据复制并删除了我复制到的内存。
    • "由于没有剩余引用,因此您不可能意外访问已删除的本机对象" FALSE。终结器队列中的其他对象可能仍会尝试使用它。
    • 投反对票的湿毯子先生又出现了。关于管道的有趣对话,让我们看看它去哪里获得洞察力。卡敦克,结束。
    猜你喜欢
    • 2023-03-10
    • 2011-02-05
    • 1970-01-01
    • 2011-01-10
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    • 2012-01-14
    • 1970-01-01
    相关资源
    最近更新 更多