Boost logo

Boost :

Subject: Re: [boost] Looking for thoughts on a new smart pointer: shared_ptr_nonnull
From: Thorsten Ottosen (thorsten.ottosen_at_[hidden])
Date: 2013-10-03 11:59:48


On 03-10-2013 17:04, Matt Calabrese wrote:
> On Thu, Oct 3, 2013 at 7:23 AM, Thorsten Ottosen <
> thorsten.ottosen_at_[hidden]> wrote:
>
>> 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).

I can't create a broken std::vector by means of the constructor. At
least I don't know how to. WhenI think about it, std::string can crash
if you pass it null_ptr. Has anybody profitted from that? It leads to
subtle run-time bugs, and I ran into that a few months back.

> It's pretty easy to come up with examples -- again, any
> function with specified preconditions can do potentially this.

It's not just any function. It's the constructor.

> 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?"

Yes, I'm well aware of the different discussion on this matter. I've
studied this subject more than most. Notice Andrei quotes my wg21 paper
with Lawrence Crowl in the end.

> 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 forget that some people prefer to provide a nice log message and
warn the users in a nice way instead of crashing the program.

Anyway, if I had to design this class, I would do the following:

a) don't provide any public constructor that takes a pointer
b) let all construction happen via make_non_null_shared( ... )

This should remove the need for validating anything, and is therefore
the least error-prone and canonical solution (there is not even a need
to assert anything).

-Thorsten


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk