Re: We do not use C++ exceptions at Google
"Frank Birbacher"
Well, ok, my example was missing documentation:
/** handlesFoo
* @param obj MUST NOT BE NULL
*/
void handleFoo(Foo* const obj)
{
//first thing to do:
assert(NULL != 0);
//...
}
Right, code is broken. Right, missing "if" after "maybeAssignPointer".
But which style of "handleFoo" will let me discover and fix the error
earlier? The assert will report the error right away (at runtime, if
that branch was taken) and also it issues debugging information. UB will
not necessarily. I think it is important to discover errors early, isn't
it?
For the assert to kick in you need at least test cases that run the code
with the needed inputs. If you have comprehensive tests, It is not likely,
that the reference-using version will pass them. (Yeah, UB has that chance,
still unlikely for this particular case -- you not just need 0 be
dereference-able memory, but also having a valid object there that makes the
good test results...)
The main working defense is reviewing the code. When you review the call
site, for the pointer-using version you need to look up the dox. For the
reference case however the constraint is implicit. *fooInstance is at your
eyes, and you ask the question: it surely got a a value? While if the
pointer is just passed forward, it is not an obvious at all.
If I compare this with the code I write, I observe:
- I don't have any "assert" statements in my own code
In general, or for such cases?
In general.
If all the code is light, functions very short, everything obvious at
glance, and the design is completely sound, it is okay. Can be.
In practice that is a rare situation. There are many "arbitrary"
constraints, non-obvious design decisions, "evolutuion", long functions,
etc, asserts serve a good double purpose documenting checkpoint conditions
and catching unintended use attempts.
They also make such code easier to review.
Guess dereferencing null auto_ptr is just UB. You should treat
shared_ptr
that way too, despite its asserting skills.
Well, auto_ptr is defined by the standard (many implementations out
there), shared_ptr by its source code (only one implementation).
shared_ptr became standard too in TR1. If you mean the original boost
version, it is also defined in the dox, not reading the source. I'm pretty
sure if there's an assert in the code the dox will not state that as
behavior.
I can
look at the source code and see asserts all over the place. They even
make sense to me.
Sure, they are not ad-hoc, but follow the 'precondition' section of
documentation (and later possibly others).
Exit is bette than UB, but we
really want correct programs that do the job, don't we? ;-) If there's
a
chance the pointer is empty, it must not be just dereferenced.
If there is a chance to get it wrong, it will be wrong. So sooner or
later I might dereference a NULL pointer. So if the program despite my
error of a NULL pointer will assert (case "handleFoo") instead of doing
_anything_ ("handleFooRef") I'll be happy.
Here you assume the 'chance' of getting wrong comes from Heavens. In fact
you have fair control over it. There indeed is a 'Murphy-threshold', but
if your project actually ever approaches it, you can be glad.
My experience shows just asserts, and especially bending code to AVOID more
implicit meaning will not get you there. (Though your practice can still
be better than others, non-quality has a deal of elbowroom ;)
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]