Use a `not_null<T>` to indicate that "null" is not a valid value
Reason
Clarity. A function with a not_null<T> parameter makes it clear that the caller of the function is responsible for any nullptr checks that might be necessary. Similarly, a function with a return value of not_null<T> makes it clear that the caller of the function does not need to check for nullptr.
Example
not_null<T*> makes it obvious to a reader (human or machine) that a test for nullptr is not necessary before dereference. Additionally, when debugging, owner<T*> and not_null<T> can be instrumented to check for correctness.
Consider:
int length(Record* p);
When I call length(p) should I check if p is nullptr first? Should the implementation of length() check if p is nullptr?
// it is the caller's job to make sure p != nullptr
int length(not_null<Record*> p);
// the implementor of length() must assume that p == nullptr is possible
int length(Record* p);
Note
A not_null<T*> is assumed not to be the nullptr; a T* might be the nullptr; both can be represented in memory as a T* (so no run-time overhead is implied).
Note
not_null is not just for built-in pointers. It works for unique_ptr, shared_ptr, and other pointer-like types.
Enforcement
- (Simple) Warn if a raw pointer is dereferenced without being tested against
nullptr(or equivalent) within a function, suggest it is declarednot_nullinstead. - (Simple) Error if a raw pointer is sometimes dereferenced after first being tested against
nullptr(or equivalent) within the function and sometimes is not. - (Simple) Warn if a
not_nullpointer is tested againstnullptrwithin a function.