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 null
. Then in my calling function I would just check if(tResult != null) { ... }
In C++, I'm finding out that I can't return a null
value 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.
This is what my code looks like right now:
class Node { Attr& getAttribute(const string& attribute_name) const { //search collection //if found at i return attributes[i]; //if not found return NULL; // what should this be? } private: vector<Attr> attributes; }
How can I change it so I can give that kind of marker?
In C++, I can think of 3 different flavors of setting up a method that finds an object. Object *findObject(Key &key); Return null when an object can't be found. Nice and simple.
In Java, a null value can be assigned to an object reference of any type to indicate that it points to nothing. The compiler assigns null to any uninitialized static and instance members of reference type. In the absence of a constructor, the getArticles() and getName() methods will return a null reference.
Yes, it is totally fine to return NULL.
Returning null Creates More Work An ideal function, like an assistant cook, will encapsulate work and produce something useful. A function that returns a null reference achieves neither goal. Returning null is like throwing a time bomb into the software. Other code must a guard against null with if and else statements.
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 nullptr; }
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.)
There are several possible answers here. You want to return something that might exist. Here are some options, ranging from my least preferred to most preferred:
Return by reference, and signal can-not-find by exception.
Attr& getAttribute(const string& attribute_name) const { //search collection //if found at i return attributes[i]; //if not found throw no_such_attribute_error; }
It's likely that not finding attributes is a normal part of execution, and hence not very exceptional. The handling for this would be noisy. A null value cannot be returned because it's undefined behaviour to have null references.
Return by pointer
Attr* getAttribute(const string& attribute_name) const { //search collection //if found at i return &attributes[i]; //if not found return nullptr; }
It's easy to forget to check whether a result from getAttribute would be a non-NULL pointer, and is an easy source of bugs.
Use Boost.Optional
boost::optional<Attr&> getAttribute(const string& attribute_name) const { //search collection //if found at i return attributes[i]; //if not found return boost::optional<Attr&>(); }
A boost::optional signifies exactly what is going on here, and has easy methods for inspecting whether such an attribute was found.
Side note: std::optional was recently voted into C++17, so this will be a "standard" thing in the near future.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With