Question

I have a class which acts as a cache. It has the following private member:

std::map<std::string, Foo> _cache;

I need to write a getter for this cache which returns a reference, pointer, iterator or smart pointer to a Foo object stored in the cache. I want the client to be able to update the Foo object if required via the getter.

However, I don't want the getter to throw if the item is not found in the cache. Instead the client should test the returned value to determine if the item was found. However, I can be convinced to throw if you recommend this approach.

What return type would you recommend for my getter?

I'm using boost and C++98.

Was it helpful?

Solution

Sounds like you need a boost::optional<Foo&> return value (optional references). Your code should look like this:

class YourCache {
    std::map<std::string, Foo> _cache;
public:
    boost::optional<Foo&> FooByName(const std::string& name)
    {
        std::map<std::string, Foo>::iterator itr = _cache.find(name);
        if(_cache.end() == itr)
            return boost::none;
        return boost::optional<Foo&>(itr->second);
    }
};
  • getter doesn't throw :)
  • respects the already existing implementation of _cache (you don't have to change it to store smart pointers - or pointers in general)
  • gives no direct access to memory in client code (like returning Foo* would)
  • expresses the intent in the best way ("the return value is optional/could be missing")
  • offers an explicit and natural interface in client code:

For example:

// client code:
if (boost::optional<Foo&> result = YourCache.FooByName("FOO")) {
    // only run if result is in cache
    result->bar();
}

OTHER TIPS

In your case references are out of question due to possibility of returning a null pointer. An iterator is a no go either, as you can't test, if it actually points to an element without access to .end() function of the cache, which is a private member. Unless you provide an interface to test is, but that's an overkill.

The only other option is to return a pointer. However that way you'd have to guarantee that the pointer remains valid throughout the whole time a caller uses it. One way to do it is to implement a map of shared pointers, that is:

std::map<std::string, boost::shared_ptr<Foo> > _cache;

That way, even if the object is thrown out of the cache, the caller would still be left with a valid pointer. And shared_ptr can be bool tested, so in case an item is not found in the cache, you could return an empty shared_ptr.

But too little is known about the context of the cache to tell you more (eg if synchronisation is needed, etc).

Use a boost::optional holding a Foo reference as your return value for your getter.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top