Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it legal to call delete on a null pointer of an incomplete type?

And if so, why does the following code give me the warning

note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined

?

struct C;

int main()
{
    C *c = nullptr;

    delete c;

    return 0;
}

I understand why it might be undefined behavior in the general case if C has non-trivial/virtual destructors, but doesn't the standard guarantee/define that delete on nullptr is always a noop no matter the situation?

To reiterate: I'm asking specifically about the case where the pointer to incomplete type is nullptr!

like image 723
Dan M. Avatar asked Nov 17 '17 15:11

Dan M.


People also ask

Can you call delete on a null pointer?

What happens when delete is used for a NULL pointer? Explanation: Deleting a null pointer has no effect, so it is not necessary to check for a null pointer before calling delete.

What is the effect of using delete for null pointer?

Deleting a null pointer has no effect.

What is do not cast or delete pointers to incomplete classes?

Casting pointers or references to incomplete classes can result in bad addresses. Deleting a pointer to an incomplete class results in undefined behavior if the class has a nontrivial destructor. Doing so can cause program termination, a runtime signal, or resource leaks.

Does delete check for null?

[16.8] Do I need to check for NULL before delete p? No! The C++ language guarantees that delete p will do nothing if p is equal to NULL.


1 Answers

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, ..."

like image 107
Nicol Bolas Avatar answered Oct 21 '22 12:10

Nicol Bolas