This is fine, and non-normative text in the standard suggests the same thing:
[C++11: 5.3.5/2]:
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 (1.8) representing a base class of such an object (Clause 10). If not, the behavior is undefined. 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. If not, the behavior is undefined. [ Note: this means that the syntax of the delete-expression must match the type of the object allocated by new
, not the syntax of the new-expression. —end note ] [ Note: a pointer to a const type can be the operand of a delete-expression; it is not necessary to cast away the constness (5.2.11) of the pointer expression before it is used as the operand of the delete-expression. —end note ]
There is a possible controversy stemming from the following passages:
[C++11: 5.3.5/3]:
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.
Though the intent of this passage appears to me only to be handling polymorphism, combined with the following passage it may be interpreted to mean that, strictly speaking, your code actually invokes undefined behaviour:
[C++11: 3.9.3/1]:
[..] The cv-qualified or cv-unqualified versions of a type are distinct types; [..]
However, I'm reasonably confident that this can be treated as a wording defect in the standard; the intent seems clear to me.
Likewise, this rule could even suggest that the program will not compile:
[C++11: 12.5.4]:
[..] If a delete-expression begins with a unary ::
operator, the deallocation function’s name is looked up in global scope. Otherwise, if the delete-expression is used to deallocate a class object whose static type has a virtual destructor, the deallocation function is the one selected at the point of definition of the dynamic type’s virtual destructor (12.4). Otherwise, if the delete-expression is used to deallocate an object of class T
or array thereof, the static and dynamic types of the object shall be identical and the deallocation function’s name is looked up in the scope of T. If this lookup fails to find the name, the name is looked up in the global scope. If the result of the lookup is ambiguous or inaccessible, or if the lookup selects a placement deallocation function, the program is ill-formed.
But again, this is not the intent of the rule, which addresses polymorphism in the absence of a virtual destructor, and genuine ambiguities across multiple class declarations.
To sum up, your best bet when interpreting the wording of these rules is still on the non-normative but very clear note we started with.