The standard says ([expr.delete]/5):
If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined.
So if T
has a non-trivial destructor or has an operator delete
overload, you get UB. Nothing is said about the UB being based on the value of the pointer (ie: whether it's a null pointer or not).
On what "object being deleted" mean?
One could consider that "object being deleted" means that this clause only applies to delete
calls on actual objects. And therefore, if you pass a null pointer, it does not apply.
First, the rest of the standard discussion about the behavior of delete
explicitly calls out that its behavior does not apply to null pointers. [expr.delete]/6&7 both start with "If the value of the operand of the delete-expression is not a null pointer value". Paragraph 5 explicitly does not contain these words. Therefore, we must assume it does apply to null pointers.
Second, what would the meaning of "object being deleted" be if it were passed a null pointer? After all, there is no "object" there.
Well, consider what it means to interpret this text if "object being deleted" talks specifically about the object at the end of that pointer. Well, what happens if you're deleting an array of incomplete classes with non-trivial destructors?
By that logic, this clause does not apply, whether the pointer is null or not. Why? Because the "object being deleted" is of an array type, not a class type. And therefore, this clause cannot apply. Which means that a compiler must be able to invoke delete[]
on an array of incomplete classes.
But that's impossible to implement; it would require the compiler to be able to track down code that doesn't exist yet.
So either the "object being deleted" is intended to refer to std::remove_pointer_t<std::decay_t<decltype(expr)>>
, or the standard requires behavior that is impossible to implement. The standard wording could probably be cleaned up a bit, replacing "If the object being deleted has incomplete class type at the point of deletion" with "If T
is a pointer to U
or an array of U
, and U
has incomplete class type at the point of deletion, ..."