Why is there no “NULL reference” in C++?

2020-06-14 06:18发布

问题:

I was reading the C++ FAQ - "8.6 - When should I use references, and when should I use pointers?" and in particular this statement:

Use references when you can, and pointers when you have to.

...

The exception to the above is where a function's parameter or return value needs a "sentinel" reference — a reference that does not refer to an object. This is usually best done by returning/taking a pointer, and giving the NULL pointer this special significance (references must always alias objects, not a dereferenced NULL pointer).

From what I've seen, the need for a "sentinel" reference is indeed often the reason to use pointers instead of references. What I'm wondering is: why doesn't C++ have a special "NULL value" for references? It seems it would make pointers almost unnecessary, which would solve many problems.

So why wasn't it part of the language specification?

Edit:

I'm not sure my question is clear - I guess I'm not asking litterally about NULL references. Most often I read that in C++ "the reference is the object". And, in most OOP languages, objects can be NULL - Pascal, C#, Java, JavaScript, PHP, etc. in all these you can do someObject = null or someObject := nil. In fact, Pascal also supports pointers but still allows objects to be nil, since it has its use. So why is C++ somehow special and doesn't have a NULL object? Was it just an overlook or an actual decision?

回答1:

Because a reference carries the semantic that it points to a valid memory address that never changes; i.e. that dereferencing it is safe/defined and so no NULL checks are required. References cannot be reassigned by design.

You use a pointer when the var can be NULL and client code has to handle that case. You use a reference when you can guarantee a valid/initialised memory address.

One example of using pointers is as a member of a class to store a "reference" to some instance that might not be known or able to be initialised at class construction time. However, member references must be initialised at construction time (via initialiser lists) and their assignment cannot be deferred.

If you allow a null reference it is then no different to a pointer besides syntax (the same NULL checks would need to take place.)

Update:

"And, in most OOP languages, objects can be NULL - Pascal, C#, Java, JavaScript, PHP, etc. [...] So why is C++ somehow special and doesn't have a NULL object? Was it just an overlook or an actual decision?"

I think you are a bit confused about this. Java and C# etc. might give the impression of "NULL objects", but these object references are more or less like a C++ pointer with simpler syntax, GC instrumentation and exception throwing. In those languages if you operate on a "Null Object" you will get some kind of exception like NullReferenceException (C#). Hell, in Java its called a NullPointerException.

You have to check for null before you can use them safely. Kind of like C++ pointers (except in most managed languages, pointers are initialised to NULL by default, whereas in C++ its usually up to you to take care of setting the initial pointer value (otherwise undefined/whatever memory was already there)).

The C++ view is about having choice, and hence being verbose:

  • Use a plain pointer to do how you please, checking NULL where necessary.
  • Use references which have a compiler-enforced validity semantic/constraint.
  • Roll your own smart pointers that do bookkeeping and behave whichever way you want them to.
  • Using void pointers (cautiously!) to reference an untyped block of memory if ever required.


回答2:

Please have a look at differences between pointers and references - while the standard leaves it open how references are implemented, they are at the moment always implemented as pointers.

Which means that the main difference between them is a) semantics b) pointers can be reseated c) pointers can be null.

So the short answer is, this was done on purpose. When you as programmer see a reference you should know that a) that reference is populated b) it won't change (and c) you can use it with the same semantics as an object).

Would the standard allow a null reference, you would always have to check for null before using a reference, which was not wanted.

Edit:

Regarding your edit, I guess the confusion here might stem from the fact that most simpler OO languages hide what is going on. To take Java as example, while it looks like you have NULL objects, and can assign them, you really can't - what is really going on is that Java only has pointers, and can assign null values to those pointers. Since it is impossible to actually have objects directly in Java, they do away with pointer semantics and treat the pointer as the object. C++ is simply more powerful - and error prone (Java enthusiast would say that stack user class instances are not required, and the decision to not have them in Java was driven to reduce complexity, and make Java easier to use). It also follows that, since Java doesn't have objects, it doesn't have references. What really doesn't help, though, is that Java calls what a C++ person would call a pass-by-value of a pointer a pass-by-reference.



回答3:

A C++ reference is not a reference in the sense that most other languages use the term; it is more like an alias. Using a C++ reference does not involve "dereferencing" it in the same way you dereference a pointer; it effectively is the object assigned to it.

There isn't really such a thing as a null object instance, so you can't create a C++ reference to such a thing. In other languages a null reference is the equivalent of a C++ null pointer; it doesn't actually contain anything.

Now, regarding your other thoughts: 1. having un-nullable references is a good thing to my mind; it means you get all the benefits of passing by reference with none of the requirement to check for nulls all over the place. 2. nullable references do not replace pointers... if you need to do memory or IO work at a low level, you're going to want raw access to memory and memory-mapped devices. You can take a look at C# (or C++/CLR), which has managed references and unmanaged pointers for precisely this reason.



回答4:

Reference by definition should be associated with another variable or object. So an empty or null reference sort of violates it purpose of existence.

Technically that would mean you start with a null reference, then ASSIGN it to some variable or may be latter reassign to another variable. This is simply NOT what reference was meant to be created for.

There are several other uses of pointers that reference can simply not replicate. Such as referring to a large chunk of complex data (a sequence of bytes) with a small amount of memory using a pointer and pass that around as frequently as needed by spending only 8 bytes or so for pointer. You cannot do that with a reference without wasting equal memory.

Reference would always be tied to a type, which is not the case with pointer.



回答5:

Reference must refer to something, so, null reference is not available.
C has no references and we can use only pointers in this language, so, this is compatibility with C language