Reading http://www.cprogramming.com/tutorial/references.html, it says:
In general, references should always be valid because you must always initialize a reference. This means that barring some bizarre circumstances (see below), you can be certain that using a reference is just like using a plain old non-reference variable. You don't need to check to make sure that a reference isn't pointing to NULL, and you won't get bitten by an uninitialized reference that you forgot to allocate memory for.
My question is how do I know that the object's memory hasn't been freed/deleted AFTER you've initialized the reference.
What it comes down to is that I can't take this advice on faith and I need a better explanation.
Can anyone shed some light?
In C++, references are primarily intended to be used as the parameters and return types of functions. In the case of a parameter, a reference cannot refer to an object that no longer exists (assuming a single threaded program) because of the nature of a function call. In the case of a return value, one should restrict oneself to either returning class member variables whose lifetimes are longer than the function call, or reference parameters that are passed in to the function.
You can't know if references are invalid:
There is no way to know if your reference is referencing valid memory except by taking care of how you use references. For example you don't want to use a reference with something created on the heap if you are unsure when the memory will be deleted.
You also can never know whether the pointer you are using is pointing to valid memory or not as well.
You can do NULL checks with both pointers and references but typically you would never do a NULL check with a reference because no one would ever write code like this:
When to use a reference?
You probably want to use references in cases like this:
Shooting yourself in the foot is hard with references:
It's much harder to shoot yourself in the foot with references than it is with pointers.
For example:
You can't do this sort of thing with references since a reference must be initialized with it's value. And you can only initialize it with values that are in your scope.
You can still shoot yourself in the foot with references, but you have to REALLY try to do it.
For example:
You need to maintain sanity of your variables -- i.e., only pass a reference/pointer to some function if you know the function scope will not outlive you reference/pointer.
If you go and free some handle and then try to use said reference you will be reading free'd memory.
There is no syntax to check whether reference is valid. You can test pointer for NULL, but there is no valid/invalid test for a reference. Of course, referenced object can be released or overwritten by some buggy code. The same situation is for pointers: if non-NULL pointer points to released object, you cannot test this.
I think you could benefit from a simple parallelism:
T &
is similar toT * const
T const &
is similar toT const * const
References are very similar to
const
in their intent, they carry a meaning and thus help write clearer code, but don't provide different runtime behavior.Now to answer your question: yes it is possible that a reference be null or invalid. You can test for a null reference (
T& t = ; if (&t == 0)
) but it should not happen >> by contract a reference is valid.When to use reference vs pointer ? Use a pointer if:
In any other case, use a reference.
Some examples:
Passing arguments:
Attributes:
Functionally references and pointers play the very same role. It's just a matter of contract. And unfortunately, both can invoke Undefined Behavior if you delete the object they refer to, there's no winner there ;)
C++ references are aliases. The effect of this is that dereferences to pointers don't necessarily happen where they appear, they happen where they are evaluated. Taking a reference to an object doesn't evaluate the object, it aliases it. Using the reference is what evaluates the object. C++ cannot guarantee references are valid; if it does, all C++ compilers are broken. The only way to do so is to eliminate all possiblity of dynamic allocation with references. In practice, the assumption is that a reference is a valid object. Since *NULL is undefined & invalid, it follows that for p = NULL, *p is also undefined. The problem with C++ is *p will be effectively passed to a function, or delayed in its evaluation until which time the reference is actually used. Arguing that it is undefined is not the point of the asker's question. If it were illegal, the compiler would enforce it, and so would the standard. Neither does, that I am aware of.
1) You can test a reference for aliasing a NULL pointer, &r is simply &(whatever r aliases to) (EDIT)
2) When passing a "dereferenced" pointer (*i) as a reference parameter, the dereference doesn't happen at the callsite, it may never happen, because it is a reference (references are aliases, not evaluations). That is the optimization of references. If they were evaluated at the callsite, either the compiler is inserting extra code, or it would be a call by value and less performant than a pointer.
Yes, the reference itself is not NULL, it is invalid, just as *NULL is invalid. It is the delaying of evaluation of dereference expressions that is not consistent with claiming it is impossible to have an invalid reference.
EDIT: Changed my example as it has been misconstrued as suggestion for testing references, not what I wanted to demonstrate. I only wanted to demonstrate the invalid reference.