C++中的软(非弱)引用 - 可能吗?有实现吗?

7
在C++中,我正在使用boost::shared_ptrboost::weak_ptr来自动删除不再需要的对象。我知道这些是通过引用计数实现的。
在Java中,内存由垃圾收集器管理,将内置对象引用视为强引用WeakReference视为弱引用SoftReference则介于两者之间(可能会被GC回收,但也可能在GC后幸存),这对于缓存对象并在空闲内存不足时立即丢弃它们非常方便。
所以现在我又回到了C++,我想念拥有软引用的舒适感。我想知道在引用计数下是否实用软引用。当最后一个强引用到对象被清除,并且仍然存在一个软引用时,它将在什么时候被删除?我可以想到一些方案,但没有一个看起来聪明。

如果有适当的软引用语义和引用计数,我想知道是否已经实现了这一点,也许以与 boost::shared_ptr (或 C++ TR1 等效的 std::shared_ptr) 兼容的方式。

如果两个问题的答案都是否定的,那么在对象缓存场景中有哪些替代方案呢?

编辑: 当缓存实际上是有用的时候,我当然是在谈论一个情况,因为构造这些对象是昂贵的(考虑到对数据库的多次访问和网络查询),但是又有太多的对象无法永久保留。


1
它到底是什么鬼东西,软引用? - Puppy
3
我也不明白,可能是某种参考文献。 - Amnon
4
“When it's at home” 是一个词组,意思是……呃……实际上没什么意义。"What on earth is a soft reference when it's at home?" 的意思是 "What (on earth) is a soft reference?" - Brian Hooper
2
@JUST:如果你是在回复我的评论,那只是一个玩笑,虽然有点无聊。 - Amnon
5
@Amnon:它是一个柔软的球,而不是一个弱的球。 - JUST MY correct OPINION
显示剩余6条评论
5个回答

7

正如其他人指出的那样,你可以在Boost库中找到引用计数指针(以及它们的对应项),但是“软引用”概念缺少对运行时环境内存限制的一些认识。例如,在Java中,SoftReference在其功能上与WeakReference没有实质性的区别;相反,两种引用类型在面对内存压力时运行时如何保留或驱逐它们的契约不同。

为了在C++中模仿这种行为,您需要构建一个内存感知的引用缓存,该缓存将在应用程序的其余部分弱引用的对象上持有强引用。当缓存确定应用程序正在刮擦其内存使用情况的天花板 - 或任何其他限制性标准 - 时,它将释放强引用,将对象“交出”(达到零引用计数)并允许后续检测无效的弱引用。

让我问一下...这不是垃圾回收器所做的事情吗?在程序需要时回收内存? - Coyote21
是的,垃圾收集器可以使先前分配给不再可达对象的内存对新对象可用,可以急切地或仅在需要时进行。问题不在于如何集成垃圾收集器,而在于是否可以模拟收集器的压力感知。在C++中使用强指针和弱指针提供了一种垃圾收集方式,但无法表达“仅在需要更多内存时固定对象”的愿望。强指针无条件固定,弱指针根本不固定。软指针介于这些极端之间。 - seh

2
如果您真的想复制这种行为,可以使用垃圾收集器(例如:http://www.hpl.hp.com/personal/Hans_Boehm/gc/),并使用它来处理您的对象或一部分对象,其中使用SoftReferences会很有用。
但我更倾向于采用更符合C++本机的解决方案,而不是复制Java的行为 - 但这并不妨碍您这样做。

1

你可以实现自己的LRU缓存,并与这样的缓存相关联的新智能指针。我认为Boost或标准C++中没有这样的结构(至少我脑海中没有)。如果你正在做一个Web应用程序或其他什么东西...你可以使用libmemcached,它是memcached的C接口。

我很难想象在构建/销毁此类对象会如此昂贵的情况下...而重新初始化则很便宜... LRU缓存会变得有用。但如果你真的需要一个,你有工具来实际构建它。


0

您可以使用类似buffcacher的工具将软引用数据移出应用程序,存储到操作系统中。

我不知道是否有现成的库可以实现这个功能,我只是自己动手写了一个。

它非常快速和公平,因此在Web服务器等任务中缓存“安全cookie”的验证等看似微小的任务也变得非常实用。


-2

不,C++ 中没有这样的东西,也不应该有。每个对象都有重要的作用。如果它没有作用,为什么你还要保留它呢?以这种方式保留对象会导致内存泄漏。如果你需要一个对象,你就需要它。如果不需要,就销毁它。有用和无用之间没有中间状态,它要么有用,要么没用。

如果你非常需要,编写自己的垃圾回收器并实现这样的功能并不是不可能。但我建议尽量避免需要或使用它们。

编辑:在对象缓存中,人们通常使用 LRU 缓存。当你缓存未命中时,最近最少使用的对象的引用将被销毁(如果缓存已满),新对象将被创建并放置为最近使用的对象,并将所有其他对象向下移动。然而,在 C++ 中通常需要在实际需要缓存策略之前从磁盘检索项目。大多数对象的创建成本并不是很高。


3
我不确定我是否理解Brian所描述的软引用是如何造成内存泄漏,而LRU缓存则不会。你要么需要该对象,要么就不需要。 - Dennis Zickefoose
1
针对您的编辑,我也编辑了我的答案。我忘记提到许多对象创建成本相当高昂。最近最少使用的策略实际上是一个好主意。无论如何,我在思考是否需要将其手动放入缓存管理对象的实现中,或者是否有类似的功能可以放入类似于弱引用的东西中。 - Lena Schimmel
1
@Dennis:LRU 有固定的大小,可以进行清理,由拥有该对象的控制。软引用是不受控制的。如果您实现 LRU,则对该内存具有控制权。如果使用软引用,则任何人都可以使用软引用。LRU 缓存具有明确定义和所有权。而软引用则是众所周知的。 - Puppy
2
“Gaggle of everybody” = 如果有空间,这个对象值得拥有,如果没有空间,则不值得。 “LRU cache” = 我将使用精确的1GB内存,我不在乎这是否意味着您的其他应用程序无法运行。在桌面操作系统上,内存耗尽是一个罕见的问题,并且不需要应用程序方面的太多技巧。 “如果有空间”基本上总是正确的。在受限系统上,应用程序相互合作使用内存可能非常重要,而软引用是一种(相对钝的)工具来实现这一点。 - Steve Jessop
1
这太疯狂了。使用固定大小的缓存不如使用动态缓存高效,后者可以根据外部资源因素(例如可用内存)进行扩展。 - Will
显示剩余2条评论

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