Soft (not: weak) references in C++ - Is it possible? Is there an implementation?

In C++ I'm using boost::shared_ptr and boost::weak_ptr to automatically delete objects that are no longer needed. I know these work with reference counting.

In Java, memory is managed by a garbage collector, which consideres the built-in object references as strong, WeakReference as weak and SoftReference as something in between (may be collected by the GC, but may as well survive the GC), which is really handy for caching objects for some time, but throwing them away as soon as free memory is getting low.

So now I'm back in C++ and I miss the comfort of having soft references. I wonder if soft referencing is practicable with reference counting at all. When the last strong reference to an object is cleared, and there remains a soft reference, when would it be deleted after all? I could think of some schemes, but none of them seem clever to me.

Just in case there are proper semantics for soft references along with reference counting, I wonder if this has already been implemented, maybe in a way that's even compatible with boost::shared_ptr (or the C++ TR1 equivalent std::shared_ptr for that matter).

If the answer to both questions is no, what are the alternatives in an object caching scenario?

EDIT: Of course I'm talking of a situation when caching is actually useful, because the objects are costly to construct (think of several access to a database and queries of a network), yet there are too many to keep them all forever.

Answers


As others pointed out, you can find referenced counted pointers (and their attendant weak counterparts) in the Boost library, but what's missing from the soft reference idea is some awareness of the runtime environment's memory constraints. In Java, for example, a SoftReference isn't materially different from a WeakReference in its capabilities; rather, it's the contract for how the runtime will preserve or evict the two kinds of references in the face of memory pressure that differs.

In order to mimic this behavior in C++, you'd have to build a memory-aware reference cache that held strong references on objects that the rest of your application would hold weakly. When the cache determined that the application was scratching its memory usage ceiling — or any other constraining criteria — it would release the strong references, surrendering the objects for "collection" (reaching the zero reference count) and allowing the weak references in use to later detect invalidation.


If you really want to replicate this behavior you may use a garbage collector (like this: http://www.hpl.hp.com/personal/Hans_Boehm/gc/) and use it to take care of your object or a subset of them, where using SoftReferences would be useful.

But I'd prefer to go for a solution more native to C++ than replicating Java bahavior - but nothing stops you of doing that.


You can implement your own LRU cache, and a new smart_pointer associated with such a cache. I don't think such a structure exists in Boost or standard C++ (off the top of my head anyway). If you are doing a web application or something... you can use libmemcached, which is the C Interface to memcached.

I find it hard to think of a situation where such an object would be so costly to construct / destroy... while it would be cheap to reinitialize... that a LRU cache would become useful. But if you really need one, you have the tools to actually build it.


You can move your soft-referenced data outside your application into the OS using something like buffcacher.

I know of no library offering this, I've only ever rolled my own.

Its so fast and fair that it gets useful to cache the validation of 'secure cookies' in webservers and other tasks that seem almost small for a conventional cache.


No, there is no such thing in C++. Nor should there be. Every object serves an important purpose. If it didn't, why do you still have it? Keeping objects around in this way is a memory leak. If you need an object, you need it. If you don't, destroy it. There is no in-between between useful and useless, either it serves a purpose or it doesn't.

If you're desperate, it is not impossible to write your own garbage collector and implement such a thing yourself. But I'd recommend against needing them or using them at all.

Edit: In object caching, people normally use LRU caches. When you have a cache miss, the reference to the least recently used object is destroyed (if the cache is full), the new object is created and put in as the most recently used, and all the others are moved down. However, you typically need to be retrieving items from disk before you actually need a caching strategy in C++. The cost of creating most objects is simply not that great.


Need Your Help