Why doesn't GCC optimize out deletion of null pointers in C++?

According to C++14 [expr.delete]/7:

If the value of the operand of the delete-expression is not a null pointer value, then:

  • [ ...omitted... ]

Otherwise, it is unspecified whether the deallocation function will be called.

So both compilers do comply with the standard, because it's unspecified whether operator delete is called for deletion of a null pointer.

Note that the godbolt online compiler just compiles the source file without linking. So the compiler at that stage must allow for the possibility that operator delete will be replaced by another source file.

As already speculated in another answer -- gcc may be angling for consistent behaviour in the case of a replacement operator delete; this implementation would mean that someone can overload that function for debug purposes and break on all invocations of the delete expression, even when it happened to be deleting a null pointer.

UPDATED: Removed speculation that this might not be a practical issue, since OP provided benchmarks showing that it in fact is.


It's a QOI issue. clang does indeed elide the test:

https://godbolt.org/g/nBSykD

main:                                   # @main
        xor     eax, eax
        ret

Standard actually states when allocation and deallocation functions shall be called and where they not. This clause (@ n4296)

The library provides default definitions for the global allocation and deallocation functions. Some global allocation and deallocation functions are replaceable (18.6.1). A C++ program shall provide at most one definition of a replaceable allocation or deallocation function. Any such function definition replaces the default version provided in the library (17.6.4.6). The following allocation and deallocation functions (18.6) are implicitly declared in global scope in each translation unit of a program.

probably would be main reason why those function calls aren't omitted arbitrary. If they were, the replacement of their implementation of library would cause incoherent function of compiled program.

In the first alternative (delete object), the value of the operand of delete may be a null pointer value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (1.8) representing a base class of such an object (Clause 10). If not, the behavior is undefined.

If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value (4.10), the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers referring to any part of the deallocated storage. Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.

...

If the value of the operand of the delete-expression is not a null pointer value, then

  • If the allocation call for the new-expression for the object to be deleted was not omitted and the allocation was not extended (5.3.4), the delete-expression shall call a deallocation function (3.7.4.2). The value returned from the allocation call of the new-expression shall be passed as the first argument to the deallocation function.

  • Otherwise, if the allocation was extended or was provided by extending the allocation of another newexpression, and the delete-expression for every other pointer value produced by a new-expression that had storage provided by the extended new-expression has been evaluated, the delete-expression shall call a deallocation function. The value returned from the allocation call of the extended new-expression shall be passed as the first argument to the deallocation function.

    • Otherwise, the delete-expression will not call a deallocation function

Otherwise, it is unspecified whether the deallocation function will be called.

Standard states what should be done if pointer is NOT null. Implying that delete in that case is noop, but to what end, is not specified.