If the operand has a class type, the operand is converted to a pointer
type by calling the above-mentioned conversion function, and the
converted operand is used in place of the original operand for the
remainder of this section.
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 ([intro.object]) representing a base class of such an
object (Clause [class.derived]).
In the second alternative (delete array), the value of the
operand of delete
may be a null pointer value or a pointer value
that resulted from
a previous array new-expression.83
A pointer to a const type can be the operand of a
delete-expression; it is not necessary to cast away the
constness ([expr.const.cast]) of the pointer expression before it is
used as the operand of the delete-expression.
In the first alternative (delete object), if the static type of
the object to be deleted is different from its dynamic type, the static type shall be
a base class of the dynamic type of the object to be deleted and the static type shall
have a virtual destructor or the behavior is undefined.
In the second
alternative (delete array) if the dynamic type of the object to
be deleted differs from its static type, the behavior is undefined.
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.
If the value of the operand of the delete-expression is not a
null pointer value, the delete-expression will invoke the
destructor (if any) for the object or the elements of the array being
deleted.
In the case of an array, the elements will be destroyed in
order of decreasing address (that is, in reverse order of the completion
of their constructor; see [class.base.init]).
Otherwise, if the allocation was extended or was provided by extending the
allocation of another new-expression, 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.
The deallocation function is called regardless of whether the destructor
for the object or some element of the array throws an exception.
—end note
]
If the value of the operand of the delete-expression is a
null pointer value, it is unspecified whether a deallocation function will be
called as described above.
An implementation provides default definitions of the global
deallocation functions operator delete for
non-arrays ([new.delete.single]) and
operator delete[] for arrays ([new.delete.array]).
If the type has new-extended alignment,
a function with a parameter of type std::align_val_t is preferred;
otherwise a function without such a parameter is preferred.
If exactly one preferred function is found,
that function is selected and the selection process terminates.
If more than one preferred function is found,
all non-preferred functions are eliminated from further consideration.
If the type is complete and if, for the second alternative (delete
array) only, the operand is a pointer to a class type with a
non-trivial destructor or a (possibly multi-dimensional) array thereof,
the function with a parameter of type std::size_t is selected.
When a delete-expression
is executed, the selected deallocation function shall be called with
the address of the most-derived object in the delete object case, or
the address of the object suitably adjusted for
the array allocation overhead ([expr.new]) in the delete array case,
as its first argument.
If a deallocation function
with a parameter of type std::align_val_t
is used,
the alignment of the type of the object to be deleted
is passed as the corresponding argument.
If a deallocation function
with a parameter of type std::size_t is used,
the size
of the most-derived type, or
of the array plus allocation overhead, respectively,
is passed as the corresponding argument.84
If this results in a call to a usual deallocation function, and either
the first argument was not the result of
a prior call to a usual allocation function or
the second argument was not the corresponding argument in said call,
the behavior is undefined ([new.delete.single], [new.delete.array]).
A lambda expression with a
lambda-introducer that consists of
empty square brackets can follow the delete keyword if the lambda expression is
enclosed in parentheses.
If the static type of the object to be deleted is complete
and is different from the dynamic type, and the destructor is not virtual, the size might
be incorrect, but that case is already undefined, as stated above.