Gavin Lambert wrote:
On 10/7/2013 6:56 PM, Quoth Matt Calabrese:
No, it's not thrown before UB occurs. By having a function with preconditions and calling that function with values that don't meet those preconditions, you have undefined behavior. If you want specified behavior, then it's not a precondition. That said, I've already also explained why it should be a precondition. Please, let's not turn this into a vector at().
Can you please restate why you think it should be a precondition? I've reread the thread and all I can find is "Initializing the object by passing a null pointer should be UB since it is a clear violation of the constructor's assumed precondition (don't pass a null pointer)" which is a statement with an assumption, not an explanation. (You go on to quite some lengths about why throwing is bad for preconditions, but not why you think it should be a precondition in the first place.)
My argument is that it should be an explicitly-validated parameter, not an assumed-valid-via-precondition one.
And again, we're only talking about the constructor here. I have no problem with operator-> etc assuming the invariant that the internal pointer is non-null, or that anything that accepts an already-constructed pointer can assume that the pointer is non-null. I just don't agree that this applies to the constructor.
While I'm not Matt Calabrese, I think I can restate why it should be a precondition *especially* on the constructor. The entire point of the proposed non-null pointers is to guarantee that the pointer is not null, so that receiving functions and storing objects can assume that it is not null. If you zero-initialize a pointer whose very purpose is not to be null, you defeat the purpose of its existence. Note how this is entirely analogous to std::sort, whose purpose is to perform an operation on a valid range. If you pass an invalid range, you defeat the purpose of the existence of the algorithm. This is why such algorithms have the precondition that you pass a valid range, IOW, that you only use them for what they were meant to be used for. Also note that a developer has the full power to decide whether they call std::sort with a valid range or not. If for whatever reason there may be any uncertainty about the validity of the iterators passed to the algorithm, it is possible to redesign the program to remove that uncertainty. Similarly, a developer can design their program to guarantee with 100% certainty that non-null pointers will never be zero-initialized. The simplest way to do that is by initializing all non-null pointers with make_shared or another non-null pointer. -Julian