我问这个问题,首先不是因为垃圾收集的优点。我问这个问题的主要原因是我知道Bjarne Stroustrup说过c++在某个时间点上会有一个垃圾收集器。

话虽如此,为什么还没有加入呢?c++已经有了一些垃圾收集器。这是那种“说起来容易做起来难”的事情吗?或者还有其他原因没有添加它(并且不会在c++ 11中添加)?

交叉链接:

c++的垃圾收集器

澄清一下,我理解c++最初创建时没有垃圾收集器的原因。我想知道为什么不能添加收集器。


当前回答

要回答关于c++的大多数“为什么”问题,请阅读c++的设计与进化

其他回答

Stroustrup在2013年的Going Native大会上对此发表了一些很好的评论。

在这个视频中跳过大约25m50s。(其实我建议你看完整个视频,但这段视频跳过了垃圾收集的内容。)

当您拥有一种非常优秀的语言,能够以直接的方式轻松(安全、可预测、易于阅读和易于教授)处理对象和值,避免(显式)使用堆时,您甚至不需要垃圾收集。

在现代c++和c++ 11中,垃圾收集不再需要,除非在有限的情况下。事实上,即使一个好的垃圾收集器内置于一个主要的c++编译器中,我认为它也不会经常使用。避免GC会更容易,而不是更难。

他举了一个例子:

void f(int n, int x) {
    Gadget *p = new Gadget{n};
    if(x<100) throw SomeException{};
    if(x<200) return;
    delete p;
}

This is unsafe in C++. But it's also unsafe in Java! In C++, if the function returns early, the delete will never be called. But if you had full garbage collection, such as in Java, you merely get a suggestion that the object will be destructed "at some point in the future" (Update: it's even worse that this. Java does not promise to call the finalizer ever - it maybe never be called). This isn't good enough if Gadget holds an open file handle, or a connection to a database, or data which you have buffered for write to a database at a later point. We want the Gadget to be destroyed as soon as it's finished, in order to free these resources as soon as possible. You don't want your database server struggling with thousands of database connections that are no longer needed - it doesn't know that your program is finished working.

那么解决方案是什么呢?有几种方法。最明显的方法,你将用于绝大多数的对象是:

void f(int n, int x) {
    Gadget p = {n};  // Just leave it on the stack (where it belongs!)
    if(x<100) throw SomeException{};
    if(x<200) return;
}

这需要更少的字符来输入。它没有新的障碍。它不需要您键入Gadget两次。对象在函数结束时被销毁。如果这是你想要的,这是非常直观的。gadget的行为与int或double相同。可预测,易读,易教。一切都是“价值”。有时是一个很大的值,但是值更容易教,因为你不需要指针(或引用)那样的“远距离操作”。

您创建的大多数对象仅用于创建它们的函数,并且可能作为输入传递给子函数。程序员不应该在返回对象时考虑“内存管理”,或者在软件的广泛分离部分之间共享对象。

范围和生命周期很重要。大多数情况下,如果生命期与作用域相同,就会更容易。这样更容易理解,也更容易教。当您想要不同的生存期时,阅读代码就会很明显地知道您正在这样做,例如通过使用shared_ptr。(或利用move-semantics或unique_ptr按值返回(大)对象。

这似乎是一个效率问题。如果我想从foo()返回一个Gadget怎么办?c++ 11的move语义使得返回大对象更容易。只需编写Gadget foo(){…它会起作用的,而且很快就会起作用。你不需要打扰&&自己,只需要按值返回,语言通常能够做必要的优化。(即使在c++ 03之前,编译器在避免不必要的复制方面做得非常好。)

正如Stroustrup在视频的其他地方所说的那样:“只有计算机科学家会坚持复制一个物体,然后破坏原始物体。(观众笑)。为什么不直接将对象移动到新位置呢?这是人类(而不是计算机科学家)所期望的。”

当您可以保证只需要一个对象的副本时,就更容易理解对象的生命周期。您可以选择您想要的生命周期策略,如果您愿意,垃圾收集就在那里。但是,当您了解其他方法的好处时,您会发现垃圾收集在首选列表的底部。

如果这对您不起作用,您可以使用unique_ptr,如果失败,可以使用shared_ptr。在内存管理方面,编写良好的c++ 11比许多其他语言更短,更容易阅读,也更容易教授。

If you want automatic garbage collection, there are good commercial and public-domain garbage collectors for C++. For applications where garbage collection is suitable, C++ is an excellent garbage collected language with a performance that compares favorably with other garbage collected languages. See The C++ Programming Language (4rd Edition) for a discussion of automatic garbage collection in C++. See also, Hans-J. Boehm's site for C and C++ garbage collection (archive). Also, C++ supports programming techniques that allow memory management to be safe and implicit without a garbage collector. I consider garbage collection a last choice and an imperfect way of handling for resource management. That does not mean that it is never useful, just that there are better approaches in many situations.

来源:http://www.stroustrup.com/bs_faq.html垃圾收集

至于为什么它没有内置它,如果我没记错的话,它是在GC出现之前发明的,我不相信这种语言有GC,有几个原因(我不相信它有GC)。C)向后兼容。

希望这能有所帮助。

原始C语言背后的一个基本原则是,内存是由一系列字节组成的,代码只需要关心这些字节在被使用的确切时刻意味着什么。现代C语言允许编译器施加额外的限制,但C语言包括——c++保留了——将指针分解为字节序列,将包含相同值的任何字节序列组装为指针,然后使用该指针访问先前的对象。

While that ability can be useful--or even indispensable--in some kinds of applications, a language that includes that ability will be very limited in its ability to support any kind of useful and reliable garbage collection. If a compiler doesn't know everything that has been done with the bits that made up a pointer, it will have no way of knowing whether information sufficient to reconstruct the pointer might exist somewhere in the universe. Since it would be possible for that information to be stored in ways that the computer wouldn't be able to access even if it knew about them (e.g. the bytes making up the pointer might have been shown on the screen long enough for someone to write them down on a piece of paper), it may be literally impossible for a computer to know whether a pointer could possibly be used in the future.

An interesting quirk of many garbage-collected frameworks is that an object reference not defined by the bit patterns contained therein, but by the relationship between the bits held in the object reference and other information held elsewhere. In C and C++, if the bit pattern stored in a pointer identifies an object, that bit pattern will identify that object until the object is explicitly destroyed. In a typical GC system, an object may be represented by a bit pattern 0x1234ABCD at one moment in time, but the next GC cycle might replace all references to 0x1234ABCD with references to 0x4321BABE, whereupon the object would be represented by the latter pattern. Even if one were to display the bit pattern associated with an object reference and then later read it back from the keyboard, there would be no expectation that the same bit pattern would be usable to identify the same object (or any object).

当我们比较c++和Java时,我们看到c++在设计时并没有考虑到隐式垃圾收集,而Java则是。

在C风格中使用任意指针这样的东西不仅不利于gc实现,而且还会破坏大量c++遗留代码的向后兼容性。

除此之外,c++是一种旨在作为独立可执行文件运行的语言,而不是具有复杂的运行时环境。

总之: 是的,在c++中添加垃圾收集是可能的,但是为了连续性,最好不要这样做。

要回答关于c++的大多数“为什么”问题,请阅读c++的设计与进化