What is the non-pointer equivalent of NULL?
There is no language-level equivalent for objects.
One option is to create a "sentinel" object that is guaranteed to compare unequal to any "real" object, and return that:
class ObjectType {
public:
static const ObjectType null;
bool operator==(const ObjectType &rhs) const { /* need an appropriate comparison test */ }
...
};
ObjectType ObjectType::null(/* something unique */);
...
ObjectType foo(const char *objectTypeName) {
if (cond) {
return objectTypeMap[objectTypeName];
} else {
return ObjectType::null;
}
}
...
if (foo(objectType) == ObjectType::null) {
std::cout << "Returned the null object\n";
}
C++17 update
C++17 introduces std::optional
as part of the standard library, the closest thing to a null object in the language, analogous to "Maybe" in other programming languages. It works much like boost::optional
described in the previous answer. One of the use cases it is intended to solve is returning an optional value from a function.
#include <iostream>
#include <optional> // Defines std::optional
std::optional<int> f(bool test) {
if (test) {
return 1;
} else {
return std::optional<int>();
}
}
int main()
{
auto ret = f(true);
// std::optional can be used as a bool
if (ret) {
std::cout << "Value for first test: " << ret.value() << '\n';
} else {
std::cout << "Value for first test: " << 0 << '\n';
}
std::cout << "Value for second test: " << (f(true)).value_or(0) << '\n';
std::cout << "Value for third test: " << (f(false)).value_or(0) << '\n';
return 0;
}
Output:
Value for first test: 1
Value for second test: 1
Value for third test: 0
The following code is not giving an error because the Standard is very conservative.
Some code structures are extremely convoluted and the compiler cannot know whether the end of the function may be reached or not. Therefore the Standard says that the compiler does not have to prove that the function correctly return a value...
However the Standard does say that should a function ends normally (no exception) without having returned a value, then Undefined Behavior is invoked (ie, anything can happen, likely a crash). Most compilers thus have a warning for such situation, for gcc and Clang you can use -Wreturn
.
Now, the principle of nullity or sentinel values is not new, and a null pointer is just one incarnation (among many).
If it does not make sense for your object to be nullable (it rarely does but can be an expedient) then you have 2 alternatives:
throw
an exception to signal the error- return a wrapper class (such as
boost::optional<ObjectType>
) which may be null
In this condition, since it is expected that Find
may not find anything, I would advise the latter in general.
Usage is simple:
boost::optional<ObjectType> MyClass::FindObjectType(char const* objectTypeName )
{
if ( objectTypeMap.find( objectTypeName ) == objectTypeMap.end() ) {
// do not print anything, it is up to the caller to decide what to do
return boost::none;
}
return objectTypeMap[ objectTypeName ];
}
And then the caller writes:
int main(int argc, char* argv[]) {
if (boost::optional<ObjectType> o = MyClass::FindObject(argv[1])) {
o->foo();
return 0;
}
Msg( "\n[C++ ERROR] No object type: %s", argv[1]);
return 1;
}