【问题标题】:Visual C++ unamanged and managedVisual C++ 非托管和托管
【发布时间】:2011-04-06 17:59:17
【问题描述】:

在 C++ 中创建托管与非托管的 .NET 对象实例有什么区别。也就是说,这些to语句有什么区别:

StreamWriter ^stream = gcnew StreamWriter(fileName);

StreamWriter *stream = new StreamWriter(fileName);

我的假设是,如果我使用 gcnew,分配给 StreamWriter 的内存将由垃圾收集器管理。或者,如果我使用指针(*)和 new 关键字,我将不得不调用 delete 来释放内存。

我真正的问题是:垃圾收集器会管理在 .NET 对象内部分配的内存吗?例如,如果一个 .NET 对象实例化了另一个对象,并且它超出了范围 - 即使我使用指针(*)和 new 关键字而不是 gcnew 和句柄(^),垃圾收集器也会管理该内存。

【问题讨论】:

  • 您的问题无法回答,第二个 sn-p 根本不是有效代码。托管类的对象必须使用 gcnew 分配。

标签: visual-c++ pointers memory-management c++-cli


【解决方案1】:

在 C++/CLI 中,你不能 new 一个 .NET 对象,你会得到类似于以下错误的东西:

错误 C2750:“System::Object”:不能在引用类型上使用“new”;改用“gcnew”

在旧的 C++ 托管扩展(/clr:oldsyntax 编译器标志)中允许将 new 用于 .NET 对象。 “托管 C++”现在已被弃用,因为它太可怕了。它已被 C++/CLI 取代,后者引入了 ^gcnew

在 C++/CLI 中,对于托管类型,您必须使用 gcnew(和 ^ 句柄),对于本机类型,您必须使用 new(和 * 指针)。如果您确实使用new 在本机堆上创建了对象,那么您有责任在完成它们后销毁它们。

理想情况下,您应该使用智能指针(如std::shared_ptrstd::unique_ptr)来管理本机堆上的对象。但是,由于您不能将本机智能指针作为 ref 类的字段,因此这并不完全简单。最简单和最通用的方法可能是编写您自己的智能指针包装器引用类,该类正确实现IDisposable

【讨论】:

  • 我认为 OP 是指一个带有指向常规 C++ 对象的指针的 CLR 对象。
  • @casablanca:您不能使用new 创建托管对象,句号。 new StreamWriter(fileName) 在 C++/CLI 中是不允许的。
  • 好的,我想我们都错过了问题的不同部分。你回答了第一部分(我最初错过了),而我正在谈论第二部分,OP 询问包含指向非托管对象的成员指针的 CLR 对象。
  • 您可以将智能指针作为 ref 类的字段。只需将其设为私有并使用 C# 样式方法包装其方法即可。
【解决方案2】:

当您使用 gcnew 创建对象时,它会绑定到垃圾收集器,而垃圾收集器将负责销毁它。

如果您使用 new,它将不会绑定到垃圾收集器,您有责任删除该对象。

澄清一下:
如果您有一个托管 C# 对象,其中包含一个非托管对象,则垃圾收集器不会删除该非托管对象。它只会在被删除之前调用托管对象的析构函数(如果存在)。您应该在析构函数中编写自己的代码来删除您创建的非托管对象。

【讨论】:

  • 我可以对垃圾收集器管理的对象调用 delete,还是应该取消引用它?我认为手动删除它们会更快。
  • 不能删除托管对象,会出现编译错误
  • 完全不正确——您可以删除托管对象的 句柄,这与删除非托管指针具有相同的语义,但调用 dispose 而不是调用析构函数。跨度>
  • 这和我写的有什么不同?您可以删除非托管对象,但 GC 不会为您隐式执行此操作。
猜你喜欢
  • 1970-01-01
  • 2011-08-31
  • 2011-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-07
相关资源
最近更新 更多