Stuart said:
Why make every little routine test over and over again something that
isn't to ever happen?
Not sure what you mean here. If you can ensure that the error cannot
happen, then there's no point in testing for it. OTOH, if you can't be
sure it won't happen, then you either take your chances for the sake of
performance (and should ask yourself if it really is all that costly to
make the check), or you put in an error check.
The question people ask is, IMO, the wrong one.
People ask: When should I pass by reference?
The right question is "When should I pass by pointer?"
and the answer is "Whenever you want to allow a pointer-to-nothing
(i.e. 0)"
which is in my experience almost never.
That is certainly not a universal assumption. I would never intentionally
pass a null pointer unless I had explicit information telling me it was OK.
I go one step further:
Pass by const reference unless the object may change.
This way when you call some code the intent is crystal clear.
I don't buy the argument that someone might then dereference a null
pointer and thus you always have to protect your code. Your interface
is a contract. At least with references you are making your intent
clear.
Assuming the person maintaining the code actually looks at the function
declaration, rather than just the call. It would appear (much to my
amazement) many C++ programmers believe a programmer should *not* look at
the actual source code where the interface is declared.
Pass by pointer and you are saying "You're allowed to pass 0".
Too often if you rely on this in other people's code you'll be
surprised by seg faults because they did not handle being passed 0 --
they really meant it had to point to something.
It seems to me your understanding of the implication of a pointer parameter
is unfounded. The only time I might assume it's safe to pass a null
pointer is if the parameter has a default null value.
You rely on other things in the contract: that the kind of object is
the kind you ask for (no static_cast downcasting to the wrong type or
your program will crash), that the relationships between objects is set
up, and so forth. For clarity of code and ease of maintainability I've
found passing by reference (const and non-const) leads to far clearer,
more maintainable and more robust code.
I certainly prefer the use of operator[](), operator.() on a reference or an
object over doing the same on a pointer. If you are working with a
conceptual design that uses shared objects, you are almost certainly going
to use some kind of smart pointer. You will have to dereference that
somewhere. This is why I find the proposal to overload operator.() and
operator.*() so attractive. Of course some people believe the new move
semantics will obviate all need for such things. Clearly that is not the
case.
At least with a const reference, I *might* be able to catch an exception.
With a non-const reference, a null pointer is a segfault.
Adding null pointer checks all
over the place instead of only in the places where the pointers can be
0 hides programmer intent while adding noise to the program and slowing
runtime. So why do it?
Because code that does use pointers, and proper error checking won't crash
due to a null pointer, but code that uses references to pass variables
*can* crash because of a null pointer being passed to a reference. So far
as I know, there is no way to protect yourself from that, other than
checking for null before dereferencing.