In C++, that distinction supposedly exists. References should never be null, while pointers can be. But there's no enforcement.
int& ref = *ptr;
ought to generate a panic for a null pointer. But it doesn't. They were so close to getting it right.For the longest time I thought this line would lead to a crash just because it seemed so obvious. So close indeed.
Im not entirely sure this helps with your point but;
The contract is that the reference is still non-null, and that the error is dereferencing the pointer. There’s two big problems with defining the behaviour of the deterrence - 0 is a valid memory address on some (ancient) platforms so for better or worse the behaviour is platform dependent.
The other is that there’s many other ways to have absolute garbage in a pointer that aren’t null.
int& foo() {
int local = 42;
return local;
}
Now, a compiler catches this case, but the point is that null isn’t the only invalid state that needs to be checked. Adding a compiler overhead of checking each pointer to every single pointer dereference wouldn’t work.Modern codebases ran with static analysis tools will catch these errors (honestly even valgrind will find most if not all of these).
> They were so close to getting it right.
The philosophy of C++ is to not introduce unnecessary overhead, and to trust the programmer. This design choice is prevalent throughout the language. They were never going to make an exception, especially for something as prevalently used as references.
There are countless examples of this "no unnecessary overhead and/or trust the programmer" choice:
- primitive types and standard containers are not thread safe - it's up to the programmer to know this and use them accordingly.
- std::unique_ptr lets you grab the underlying raw pointer, in which case it's no longer a "unique_ptr". But there are cases in which it's useful to do this (e.g. interfacing with C code), so they let you do it, and trust that you do it in a safe way. They could have made unique_ptr not support this, but then it would be less useful (or force you into copying data unnecessarily to call an API that requires a raw pointer).
> But there's no enforcement.
There's no strict enforcement, but it is undefined behaviour, so compilers can randomly choose to act as if it's enforced and simply crash your program or make it act weirdly.