I'm dang certain that this code ought to be illegal, as it clearly won't work, but it seems to be allowed by the C++0x FCD.
class X { /* ... */};
void* raw = malloc(sizeof (X));
X* p = new (raw) X(); // according to the standard, the RHS is a placement-new expression
::operator delete(p); // definitely wrong, per litb's answer
delete p; // legal? I hope not
Maybe one of you language lawyers can explain how the standard forbids this.
There's also an array form:
class X { /* ... */};
void* raw = malloc(sizeof (X));
X* p = new (raw) X[1]; // according to the standard, the RHS is a placement-new expression
::operator delete[](p); // definitely wrong, per litb's answer
delete [] p; // legal? I hope not
This is the closest question I was able to find.
EDIT: I'm just not buying the argument that the standard's language restricting arguments to function void ::operator delete(void*) apply in any meaningful way to the operand of delete in a delete-expression. At best, the connection between the two is extremely tenuous, and a number of expressions are allowed as operands to delete which are not valid to pass to void ::operator delete(void*). For example:
struct A
{
virtual ~A() {}
};
struct B1 : virtual A {};
struct B2 : virtual A {};
struct B3 : virtual A {};
struct D : virtual B1, virtual B2, virtual B3 {};
struct E : virtual B3, virtual D {};
int main( void )
{
B3* p = new E();
void* raw = malloc(sizeof (D));
B3* p2 = new (raw) D();
::operator delete(p); // definitely UB
delete p; // definitely legal
::operator delete(p2); // definitely UB
delete p2; // ???
return 0;
}
I hope this shows that whether a pointer may be passed to void operator delete(void*) has no bearing on whether that same pointer may be used as the operand of delete.
The Standard rules at [basic.stc.dynamic.deallocation]p3
Otherwise, the value supplied to
operator delete(void*)in the standard library shall be one of the values returned by a previous invocation of eitheroperator new(size_t)oroperator new(size_t, const std::nothrow_t&)in the standard library, and the value supplied tooperator delete[](void*)in the standard library shall be one of the values returned by a previous invocation of eitheroperator new[](size_t)oroperator new[](size_t, const std::nothrow_t&)in the standard library.
Your delete call will call the libraries' operator delete(void*), unless you have overwritten it. Since you haven't said anything about that, I will assume you haven't.
The "shall" above really should be something like "behavior is undefined if not" so it's not mistaken as being a diagnosable rule, which it isn't by [lib.res.on.arguments]p1. This was corrected by n3225 so it can't be mistaken anymore.
The compiler doesn't really care that p comes from a placement new call, so it won't prevent you from issuing delete on the object. In that way, your example can be considered "legal".
That won't work though, since "placement delete" operators cannot be called explicitly. They're only called implicitly if the constructor throws, so the destructor can run.
I suppose you might get away with it (on a particular compiler) if
new/deleteare implemented in terms ofmalloc/freeand- the placement
newactually uses the same mechanism for keeping track of the destructor associated with allocations as the standardnew, so that the call todeletecould find the right destructor.
But there is no way it can be portable or safe.
I found this in the library section of the standard, which is about as counter-intuitive a location (IMO) as possible:
C++0x FCD (and n3225 draft) section 18.6.1.3, [new.delete.placement]:
These functions are reserved, a C ++ program may not define functions that displace the versions in the Standard C ++ library (17.6.3). The provisions of (3.7.4) do not apply to these reserved placement forms of operator new and operator delete.
void* operator new(std::size_t size, void* ptr) throw();
void* operator new[](std::size_t size, void* ptr) throw();
void operator delete(void* ptr, void*) throw();
void operator delete[](void* ptr, void*) throw();
Still, the section defining legal expressions to pass to delete is 5.3.5, not 3.7.4.
来源:https://stackoverflow.com/questions/4418220/legality-of-using-operator-delete-on-a-pointer-obtained-from-placement-new