垃圾收集是否在标准C ++中自动进行?

时间:2009-11-08 01:31:53

标签: .net c++ garbage-collection

据我所知,在标准C ++中,每当使用new运算符时,您还必须在某些时候使用delete运算符来防止内存泄漏。这是因为C ++中没有垃圾收集。在.NET中,垃圾收集是自动的,因此无需担心内存管理。我的理解是否正确?感谢。

8 个答案:

答案 0 :(得分:19)

对它的长期回答是,每次调用new,某处,某种程度上,delete必须被调用,或者其他一些释放函数(取决于内存分配器等)。

但您不需要提供delete电话:

  1. Hans-Boehm Garbage Collector的形式存在C ++的垃圾收集。还有其他垃圾收集库。
  2. 您可以使用智能指针,它使用RAII(如果指针允许共享访问,则引用计数)以确定何时删除对象。一个好的智能指针库是Boost的smart pointer。绝大多数情况下的智能指针可以替换原始指针。
  3. 某些应用程序框架(如Qt)构建对象树,因此框架的堆分配对象存在父子关系。因此,只需要在对象上调用delete,所有子代也将自动delete
  4. 如果您不想使用这些技术中的任何一种,为了防止内存泄漏,您可以尝试使用内存检查工具。 Valgrind特别好,虽然它只适用于Linux

    至于.NET,是的,使用gcnew进行分配意味着内存由.NET跟踪,因此没有泄漏。但是,其他资源(如文件句柄等)不由GC管理。

答案 1 :(得分:9)

idiomatic高级C ++中,永远不会调用删除

C ++没有与C#中相同的标准垃圾收集器,因此从根本上说,newdelete需要配对。但是,C ++中有一些机制可以完全消除{em>显式对现代风格编写的代码的使用{/ 1}}。

首先要注意的是,在C ++中,使用delete 比在C#中使用new要少得多。这是因为在C#中,每当创建结构,类或数组的实例时都使用new,但在C ++中,只有在想要动态管理数据元素时才使用new。 C ++中的大多数数据不需要动态管理,因此可以在不使用new的情况下创建。 [换句话说,new在C#中的含义与在C ++中的含义不同。在C ++中,它专门表示动态分配,而在C#中,它用于任何构造。]

其次,每次在C ++中调用new时,返回值都应直接传递给smart pointer。智能指针将确保在适当的时候自动为您调用new

顺便说一下,除非你是一个编写低级库(或学生学习如何做)的大师,否则你永远不应该调用delete来在C ++中分配一个数组。标准库(以及Boost / TR1)提供了为您分配和管理数组的模板类。

总之,C ++不使用垃圾收集器,但它确实有自己的自动内存管理形式。这两种方法之间存在细微差别,但这两种方法都可以自动释放内存,从而消除了大多数类型的内存泄漏。

这些概念的权威性演示由C ++创建者Bjarne Stroustrup在回答问题时提供:How do I deal with memory leaks?

另见:

答案 2 :(得分:8)

关于operator new的陈述是完全正确的......但它过分简化了C ++语义。

在C ++中,可以在堆栈上或堆上创建对象:

class Foo {};

int main() {
  Foo obj1;
  Foo* obj2 = new Foo();
  delete obj2;
}

在上面的例子中,在堆栈上创建了obj1,并在堆上创建了obj2(使用new)。在显式调用delete之前,不会销毁在堆上创建的对象。但是,堆栈上的对象在超出范围时会自动销毁(即在此示例中返回main()时)。

这使得C ++中的“资源获取是初始化”成语(a.k.a.RAII)成为可能,它比基本的垃圾收集功能强大得多。需要清理的资源(堆内存,套接字,文件,数据库连接等)通常放在基于堆栈的对象中,其析构函数负责清理。

相比之下,Java和C#不允许在堆栈上构造对象,并且不保证收集将会发生,也不保证终结器将运行(我不是C#的人,所以我可能会有点错了)。因此,当你在Java / C#中获得免费的堆内存管理时,你实际上会在这些语言中获得比在C ++中更多的资源清理代码。

答案 3 :(得分:2)

是的,你是对的,在标准的C ++中(在托管的C ++或它依赖的其他变种中)你必须在每个新的后使用删除。在C#,Java和其他垃圾收集语言中,这不是必需的(实际上大多数语言都没有“delete”运算符)。

答案 4 :(得分:1)

“C ++中没有垃圾收集。”

正确。

答案 5 :(得分:1)

您可以通过两种方式使用C ++和.NET:托管或非托管。在托管模式下,.NET的垃圾收集将代表您处理释放内存;在非托管模式下,你接近C ++的正常/标准行为,所以你必须自己掌控你的记忆。

答案 6 :(得分:1)

自动垃圾收集很有用,但您仍然可以获得内存泄漏,如此问题所示:

Memory Leaks in C# WPF

它在.NET和Java中有所减少,但这并不意味着它允许自动处理错误的编码。

因此,在C ++中,您需要明确地发布您请求的内容,我认为这有时会更好,因为您知道发生了什么。我希望在.NET和Java中,垃圾收集器在调试模式下几乎没有做什么,以帮助确保人们知道他们在做什么。

答案 7 :(得分:0)

纠正你必须担心C ++上的垃圾收集

而且......有no need to worry about garbage collection on .NET

只有你有这样的密集和长脚本,你觉得需要优化,你需要关注它。

编辑:asveikau和Pavel Minaev的评论都很棒,谢谢!我过度概括了传递信息。