为了账号安全,请及时绑定邮箱和手机立即绑定

为什么C ++没有垃圾回收器?

为什么C ++没有垃圾回收器?

C++
Smart猫小萌 2019-12-07 14:28:34
首先,因为垃圾收集的优点,所以我没有问这个问题。我提出这个问题的主要原因是,我确实知道Bjarne Stroustrup曾说过C ++将在某个时间点具有垃圾回收器。话虽如此,为什么不添加呢?已经有一些C ++的垃圾收集器。这只是那些“说起来容易做起来难”的事情之一吗?还是有其他原因没有被添加(并且不会在C ++ 11中添加)?交叉链接:C ++垃圾收集器为了澄清起见,我理解C ++首次创建时没有垃圾收集器的原因。我想知道为什么不能添加收集器。
查看完整描述

3 回答

?
慕容森

TA贡献1853条经验 获得超18个赞

可以添加隐式垃圾回收,但是并没有成功。可能不仅是由于实施方面的复杂性,还因为人们没有足够快地达成普遍共识。


Bjarne Stroustrup自己的话:


我曾希望可以选择启用的垃圾收集器将成为C ++ 0x的一部分,但是我有足够的技术问题需要解决,只需详细说明这种收集器如何与语言的其余部分集成即可。 (如果提供)。与基本上所有C ++ 0x功能的情况一样,存在实验性实现。


有话题商量好了这里。


总体概述:


C ++功能非常强大,几乎可以做任何事情。因此,它不会自动将很多可能影响性能的事情推到您身上。垃圾回收可以通过智能指针轻松实现(智能对象包装带有引用计数的指针,当引用计数达到0时,这些对象会自动删除自身)。


C ++是在没有垃圾收集的情况下考虑竞争对手而构建的。与C和其他语言相比,效率是C ++必须抵制批评的主要问题。


垃圾收集有2种类型...


显式垃圾回收:


C ++ 0x将通过使用shared_ptr创建的指针进行垃圾回收


如果您想要它,则可以使用它;如果您不想要它,则不会被迫使用它。


如果您不想等待C ++ 0x,则当前还可以使用boost:shared_ptr。


隐式垃圾回收:


它没有透明的垃圾收集器。不过,它将成为未来C ++规范的重点。


为什么Tr1没有隐式垃圾回收?


C ++ 0x的tr1应该有很多东西,Bjarne Stroustrup在之前的采访中指出,tr1没有他想要的东西。


查看完整回答
反对 回复 2019-12-07
?
慕后森

TA贡献1802条经验 获得超5个赞

在这里增加辩论。


垃圾回收存在一些已知问题,对它们的了解有助于理解C ++中为什么没有垃圾回收的问题。


1.性能


第一个抱怨通常是关于性能的,但是大多数人并没有真正意识到他们在说什么。如图所示,Martin Beckett问题可能不是性能本身,而是性能的可预测性。


当前有2个广泛使用的GC系列:


标记和扫描种类

参考计数种类

该Mark And Sweep快(对整体性能的影响较小),但它从一个“冻结世界”综合症患有:即当在GC踢,一切停止,直到GC作出了清理。如果您希望构建可以在几毫秒内响应的服务器...某些事务将无法达到您的期望:)


问题Reference Counting不同:引用计数会增加开销,尤其是在多线程环境中,因为您需要具有原子计数。此外,还有参考循环的问题,因此您需要一个聪明的算法来检测这些循环并消除它们(通常也通过“冻结世界”来实现,尽管频率较低)。总体而言,截至今天,这种方法(即使通常响应速度更快或更不频繁地冻结)也比慢Mark And Sweep。


我看过埃菲尔铁塔实施者的论文,他们试图实施一个Reference Counting垃圾收集器,该垃圾收集器的全球性能与Mark And Sweep没有“冻结世界”方面的相似。它需要用于GC的单独线程(典型)。该算法有点令人恐惧(最后),但是论文很好地完成了一次介绍一个概念并展示了算法从“简单”版本到成熟版本的演变。推荐阅读,只要我能把双手放回PDF文件上即可...


2.资源获取正在初始化(RAII)


这是一个常见的习惯用法C++,您将资源的所有权包装在一个对象中以确保正确释放它们。因为我们没有垃圾回收,所以它主要用于内存,但是它在许多其他情况下也很有用:


锁(多线程,文件句柄等)

连接(到数据库,另一台服务器...)

这个想法是适当地控制对象的生存期:


只要你需要它就应该还活着

完成后应将其杀死

GC的问题是,如果它对前者有所帮助并最终保证在以后……“最终”可能还不够。如果您释放锁,那么您真的希望它现在被释放,这样它就不会阻止任何进一步的呼叫!


使用GC的语言有两种解决方法:


当堆栈分配足够时不要使用GC:通常是为了解决性能问题,但是在我们的情况下,这确实有用,因为范围定义了生命周期

using构造...但是它是显式的(弱)RAII,而在C ++中,RAII是隐式的,因此用户不能不经意间犯错误(通过省略using关键字)

3.智能指针


智能指针通常表现为处理内存中的银弹C++。我经常听到:我们毕竟不需要GC,因为我们有智能的指针。


一个再错不过了。


智能指针确实有帮助:auto_ptr并且unique_ptr使用RAII概念,的确非常有用。它们是如此简单,您可以很容易地自己编写它们。


但是,当需要共享所有权时,这会变得更加困难:您可能会在多个线程之间共享,并且计数处理存在一些细微的问题。因此,自然会走向shared_ptr。


太好了,毕竟这就是Boost的目的,但这不是灵丹妙药。实际上,主要的问题shared_ptr是它模拟了由GC实施的GC,Reference Counting但是您需要自己全部实施循环检测... Urg


当然,这很weak_ptr麻烦,但是尽管如此,shared_ptr由于使用了这些周期,但不幸的是我已经看到内存泄漏了……而且当您处于多线程环境中时,这很难检测!


4.解决方案是什么?


没有灵丹妙药,但是和往常一样,这绝对是可行的。在没有GC的情况下,需要明确所有权:


如果可能的话,宁愿在给定的时间只有一个所有者

如果没有,请确保您的类图没有与所有权有关的任何周期,并通过巧妙地应用 weak_ptr

所以的确,拥有GC很棒。但是这不是小问题。同时,我们只需要卷起袖子。


查看完整回答
反对 回复 2019-12-07
  • 3 回答
  • 0 关注
  • 390 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信