views:

471

answers:

6

I'm pretty new to C++ so I tend to design with a lot of Java-isms while I'm learning. Anyway, in Java, if I had class with a 'search' method that would return an object T from a Collection< T > that matched a specific parameter, I would return that object and if the object was not found in the collection, I would return a NULL. Then in my calling function I would just check if(T != NULL) { ... }

In C++, I'm finding out that I can't return a NULL if the object doesn't exist. I just want to return an 'indicator' of type T that notifies the calling function that no object has been found. I don't want to throw an exception because it's not really an exceptional circumstance.

class Node {
....

Attr& getAttribute(const string& attribute_name) const {
   //search collection
   //if found at i
        return attributes[i];
   //if not found
        return NULL;
}

private:
   vector<Attr> attributes;
}
A: 

If you want a NULL return value you need to use pointers instead of references.

References can't themselves be NULL.

(Note to the future comment posters: Yes you can have the address of a reference be NULL if you really really try to).

See my answer here for a list of differences between references and pointers.

Brian R. Bondy
+6  A: 

In C++, references can't be null. If you want to optionally return null if nothing is found, you need to return a pointer, not a reference:

Attr *getAttribute(const string& attribute_name) const {
   //search collection
   //if found at i
        return &attributes[i];
   //if not found
        return NULL;
}

Otherwise, if you insist on returning by reference, then you should throw an exception if the attribute isn't found.

(By the way, I'm a little worried about your method being const and returning a non-const attribute. For philosophical reasons, I'd suggest returning const Attr *. If you also may want to modify this attribute, you can overload with a non-const method returning a non-const attribute as well.)

Jesse Beder
Thanks. By the way, is this an accepted way of designing such a routine?
aduric
@aduric: Yes. References imply the result has to exist. Pointers imply the result might not exist.
Bill
A: 

You are unable to return NULL because the return type of the function is an object reference and not a pointer.

codaddict
A: 

The reason that you can't return NULL here is because you've declared your return type as Attr&. The trailing & makes the return value a "reference", which is basically a guaranteed-not-to-be-null pointer to an existing object. If you want to be able to return null, change Attr& to Attr*.

JSBangs
+9  A: 
Kaz Dragon
+1 I would just mention boost::optional first, and only briefly mention the other alternatives.
Nemanja Trifunovic
Ya I saw boost::optional mentioned somewhere but I was thinking that it required too much overhead. If using it is the best approach to these kinds of problems, I will start using it.
aduric
`boost::optional` does not involve much overhead (no dynamic allocation), which is why it's so great. Using it with polymorphic values requires wrapping references or pointers.
Matthieu M.
+2  A: 

You can easily create a static object that represents a NULL return.

class Attr;
extern Attr AttrNull;

class Node { 
.... 

Attr& getAttribute(const string& attribute_name) const { 
   //search collection 
   //if found at i 
        return attributes[i]; 
   //if not found 
        return AttrNull; 
} 

bool IsNull(const Attr& test) const {
    return &test == &AttrNull;
}

 private: 
   vector<Attr> attributes; 
};

And somewhere in a source file:

static Attr AttrNull;
Mark Ransom
Shouldn't NodeNull be of type Attr?
aduric
Good point, I'll fix the example.
Mark Ransom