Search code examples
c++memory-managementlanguage-lawyerdelete-operatorplacement-new

Legality of using delete-expression on a pointer not obtained from usual new


I wonder if this code is legal:

delete new (operator new(1)) char;

This code does the same thing, but doesn't use delete expression on a pointer obtained from placement new:

void* p = operator new(1);
new (p) char;
delete static_cast<char*>(p);

The standard rules at [expr.delete#2]:

In a single-object delete expression, the value of the operand of delete may be a null pointer value, a pointer value that resulted from a previous non-array new-expression, or a pointer to a base class subobject of an object created by such a new-expression. If not, the behavior is undefined. In an array delete expression, 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.68 If not, the behavior is undefined.

The standard does not say that new-expression does not include placement new. So I think according to the standard, the first piece of code should be legal, but the second should be illegal. Is my idea correct?

Why the standard says that? Calling operator new and constructing an object on it does almost the same thing as the new expression, but using the delete expression on the obtained pointer is not necessarily legal.

For allocating an array, the standard seems to allow this:

delete[] new (operator new[](2)) char[2];

But it should be illegal due to unspecified overhead.

Why does the standard allow that?


EDIT: According to [intro.object]/13:

Any implicit or explicit invocation of a function named operator new or operator new[] implicitly creates objects in the returned region of storage and returns a pointer to a suitable created object.

So I can even write the following code:

delete static_cast<char*>(operator new(1));

It destroys the implicitly created char object and deallocates the memory, doing the same thing as the examples above. But it's definitely illegal according to the standard because no new-expression is used.

Why doesn't the standard allow that?


Solution

  • delete new (operator new(1)) char; does appear to be legal. Like you said, the standard does not make any exceptions for placement new.

    Your second example is also legal:

    void* p = operator new(1);
    new (p) char;
    delete static_cast<char*>(p);
    

    Let's walk through what happens step by step. The call to operator new implicitly creates a char object and returns a pointer to said object1. So p starts out already pointing to a char object. The placement new expression constructs a new char object over the old one, ending the lifetime of the old object; according to the rules of the abstract machine, this magically changes the value of p such that it points to this new object; see [basic.life]/8. Finally, static_cast<char*>(p) returns a pointer pointing to that same char object. That is, this pointer has the same value as the pointer that was returned by the placement new. So if the first example is valid, so is this one.

    Note that [expr.delete]/2 does not suggest that in order for an operand to delete to be valid, there must be some sort of valid "chain of custody" from a new expression to the value that is now being deleted. It merely says "... a pointer value that resulted from a previous non-array new-expression..." The value of the pointer is all that matters. In your second example, p has the same value as the pointer returned from the placement new, thanks to [basic.life]/8.

    Regarding your third example, delete[] new (operator new(2)) char[2];, I agree that it shouldn't be legal. I suggest filing a defect report.

    1 See [intro.object]/13.