Visual C++非托管和托管

6

在C++中创建托管和非托管的.NET对象实例有什么区别?也就是说,以下两个语句之间有何不同:

StreamWriter ^stream = gcnew StreamWriter(fileName);

对比

StreamWriter *stream = new StreamWriter(fileName);

我的假设是,如果我使用gcnew关键字,为StreamWriter分配的内存将被垃圾回收器管理。另外,如果我使用指针(*)和new关键字,则必须调用delete来释放内存。

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


3
你的问题无法回答,第二段代码片段并不是有效的代码。一个托管类的对象必须使用gcnew进行分配。 - Hans Passant
2个回答

6
在C++/CLI中,你不能使用new来创建.NET对象,否则会得到类似于以下错误的信息:

error C2750: 'System::Object' : cannot use 'new' on the reference type; use 'gcnew' instead

在旧版Managed Extensions for C++(/clr:oldsyntax编译器标志)中,允许使用new来创建.NET对象。但是,“Managed C++”现已被弃用,因为它很糟糕。取而代之的是C++/CLI,引入了^gcnew
在C++/CLI中,必须使用gcnew(以及^句柄)来处理托管类型,并且必须使用new(以及*指针)来处理本机类型。如果使用new在本机堆上创建对象,则需要在使用完后负责销毁它们。
理想情况下,应该使用智能指针(如std::shared_ptrstd::unique_ptr)来管理本机堆上的对象。但由于无法将本机智能指针作为ref类的字段,因此这并不完全简单。最简单和最通用的方法可能是编写自己的智能指针包装器ref类,正确实现IDisposable

我认为OP的意思是一个带有指向常规C++对象的指针的CLR对象。 - casablanca
2
@casablanca:在C++/CLI中,你不能使用new来创建托管对象。new StreamWriter(fileName)是不被允许的。 - James McNellis
好的,我猜我们都错过了问题的不同部分。 你回答了第一部分(我最初错过了),而我在谈论第二部分,其中OP询问包含指向非托管对象的成员指针的CLR对象。 - casablanca
你可以将智能指针作为 ref 类的字段。只需将其设置为私有,并用 C# 风格的方法包装其方法即可。 - Yochai Timmer

4
当您使用gcnew创建一个对象时,它会绑定到垃圾回收器,并且垃圾回收器将负责销毁它。
如果您使用new,它不会绑定到垃圾回收器,而且删除对象的责任将落在您身上。
仅为澄清: 如果您有一个包含非托管对象的托管C#对象,则垃圾回收器不会删除非托管对象。它只会在删除之前调用托管对象的析构函数(如果存在)。您应该在析构函数中编写自己的代码以删除所创建的非托管对象。

我可以在垃圾回收器管理的对象上调用delete吗?还是应该只是取消引用它?我认为手动删除它们会更快。 - LunchMarble
您无法删除托管对象,否则将会出现编译错误。 - Yochai Timmer
1
完全不正确--您可以删除对托管对象的句柄,这与删除未管理的指针具有相同的语义,但调用dispose而不是调用析构函数。 - ildjarn
那跟我写的有什么不同呢?你可以删除非托管对象,但垃圾回收器不会隐式地为你执行此操作。 - Yochai Timmer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接