Would combining raw operator new, placement new and standard delete be legal?
guys! Out of curiosity – the following code would probably not be legal, would it?
T *p = ::operator new(sizeof(T)); // allocate memory for a T
new (p) T; // construct a T into the alloc开发者_JAVA技巧ated memory
delete p; //delete the object using the standard delete operator
No. You can only delete
what you get back from new
- no exceptions.
There's at least one circumstance in which it's clearly undefined: if you've overloaded operator new
and operator delete
for T
, then this will attempt to allocate memory using ::operator new
, but delete it using T::operator delete
. Unless your T::operator delete
is purely a wrapper around ::operator delete
, that's going to cause a problem.
Other than that, I think it's probably defined. The standard is very specific about the fact that a new expression
allocates its memory using an allocation function (§5.3.4/10), which will be ::operator new
as long as you haven't provided a T::operator new
.
Your placement new expression then initializes the object, just as described for a new expression in the first bullet point of §5.3.4/15.
Then we get to the destruction side. According to $5.3.5/1: "The delete-expression operator destroys a most derived object (1.8) or array created by a new-expression." That requires that you have used a new expression to create the object -- which you have. You've used a placement new, which is one of the possibilities for a new expression, and specified in §5.3.4/1.
The next requirements that apply seem to be: "The operand shall have a pointer type, or a class type having a single conversion function (12.3.2) to a pointer type." Again, your expression meets that as well.
I'm going to quote more requirements, without further comment, except that your code seems to meet all of them (some limit the implementation of a delete expression, not the pointer you can use in one):
(§5.3.5/2): "In the first alternative (delete object), the value of the operand of delete shall be a pointer to a non-array object or a pointer to a sub-object (1.8) representing a base class of such an object (clause 10). If not, the behavior is undefined."
(§5.3.5/3): "In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined.
(§5.3.5/4): "In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined."
(§5.3.5/6): "The delete-expression will invoke the destructor (if any) for the object or the elements of the array being deleted."
(§5.3.5/7): The delete-expression will call a deallocation function (3.7.3.2).
With the initial caveat about ::operator new
vs. T::operator new
, I think the pointer you're using in the delete expression
meets all the requirements, so the behavior should be defined.
Having said all that, I certainly hope this is purely academic interest -- even though it looks to me like the code does have defined behavior, it's a lousy idea even at very best.
Going off of DeadMG's correct assertion, there is no problem with a slight change to your code:
unsigned char* addr = new unsigned char[sizeof(MySimpleStructure)];
MySimpleStructure* p = new (addr) MySimpleStructure;
delete [] addr;
Since we're delete
ing addr
which was returned by new
there is no issue with this being legal. Of course, after addr
is deleted, p
should not be accessed (its a dangling pointer at that time). Also note that MySimpleStructure
as allocated via placement new to p
will not have its destuctor called.
精彩评论