Returning a "NULL reference" in C++?

Why "besides using pointers"? Using pointers is the way you do it in C++. Unless you define some "optional" type which has something like the isNull() function you mentioned. (or use an existing one, like boost::optional)

References are designed, and guaranteed, to never be null. Asking "so how do I make them null" is nonsensical. You use pointers when you need a "nullable reference".


You cannot do this during references, as they should never be NULL. There are basically three options, one using a pointer, the others using value semantics.

  1. With a pointer (note: this requires that the resource doesn't get destructed while the caller has a pointer to it; also make sure the caller knows it doesn't need to delete the object):

    SomeResource* SomeClass::getSomething(std::string name) {
        std::map<std::string, SomeResource>::iterator it = content_.find(name);
        if (it != content_.end()) 
            return &(*it);  
        return NULL;  
    }
    
  2. Using std::pair with a bool to indicate if the item is valid or not (note: requires that SomeResource has an appropriate default constructor and is not expensive to construct):

    std::pair<SomeResource, bool> SomeClass::getSomething(std::string name) {
        std::map<std::string, SomeResource>::iterator it = content_.find(name);
        if (it != content_.end()) 
            return std::make_pair(*it, true);  
        return std::make_pair(SomeResource(), false);  
    }
    
  3. Using boost::optional:

    boost::optional<SomeResource> SomeClass::getSomething(std::string name) {
        std::map<std::string, SomeResource>::iterator it = content_.find(name);
        if (it != content_.end()) 
            return *it;  
        return boost::optional<SomeResource>();  
    }
    

If you want value semantics and have the ability to use Boost, I'd recommend option three. The primary advantage of boost::optional over std::pair is that an unitialized boost::optional value doesn't construct the type its encapsulating. This means it works for types that have no default constructor and saves time/memory for types with a non-trivial default constructor.

I also modified your example so you're not searching the map twice (by reusing the iterator).