Subject: Re: [boost] Looking for thoughts on a new smart pointer: shared_ptr_nonnull
From: Matt Calabrese (rivorus_at_[hidden])
Date: 2013-10-03 11:04:34
On Thu, Oct 3, 2013 at 7:23 AM, Thorsten Ottosen <
> If I see a class called non_null_ptr, I pretty much expect it not to be
> null (it's an /invariant/), and use it assuming this.
Yes, of course, that's the whole point. Using an assert does not change
that. Again, you assert preconditions. When you define preconditions for a
function, it's the caller's responsibility to meet those preconditions,
which is why you assert them rather than handle them (sometimes it's not
even possible to really check the precondition).
> How many other classes allow you
> to construct an illegal object (an object where the invariant is broken?).
> I can't give any example from Boost or the standard library.
Whenever you violate any precondition of any function you are potentially
putting your program in an unreliable state, including the breaking of
invariants of that object or others (this is true of Boost and the STL and
other libraries). It's pretty easy to come up with examples -- again, any
function with specified preconditions can do potentially this. If your
function always handles checking of the precondition and doesn't break the
invariants of the object when the function exits and this is documented as
a reliable part of the function, then it's simply not a precondition, but
rather, it's an accepted argument to the function with well-defined results.
We are not making up these rules here. This is sort of the point of
preconditions. For a more detailed explanation, you can reference
Alexandrescu's post at
http://akrzemi1.wordpress.com/2013/01/04/preconditions-part-i/ under the
heading: "What if a precondition is violated?"
The point is, even if you happen to throw in a particular implementation,
if the precondition is such that the constructor cannot take a null
pointer, then the throwing behavior is never to be relied upon by the user
anyway. It's still just undefined behavior. Asserting accomplishes this,
allows your function to be noexcept, and does not open the door to people
[incorrectly] handling the exception (any handling of such an exception
doesn't get you out of UB-land since you've broken the precondition). You
have to keep in mind that when the exception is thrown, you've already told
the user that the program is in an ill-defined state anyway by way of the
precondition, so catching the exception is effectively meaningless. If you
want unraveling of the stack or catching of the exception to be worthwhile,
then you need to eliminate the precondition altogether.
-- -Matt Calabrese