Legality of Using Operator Delete on a Pointer Obtained from Placement New

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

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.

Can a call delete on the pointer which is allocated with the placement new?

EDIT1: I know that there is no placement delete. But I wonder why just
delete opetator can not delete the memory without caring how that
memory on which the pointer points is allocated?

Because each flavour of memory allocation uses some implementation specific tracking of the memory (usually a header block that precedes the user address) and this make the allocation/deallocation to work only when paired up correctly:

  • new must pair with delete
  • new[] must pair with delete[] (most implementations though forgive mixing the newand new[])
  • malloc and frieds must pair with free
  • CoTaskMemAlloc pairs with CoTaskMemFree
  • alloca pairs with nothing (stack unwinding takes care of it)
  • MyCustomAllocator pairs with MyCustomFree

Attempting to call the wrong deallocator will result in unpredictable behavior( most likely seg fault now or later). Therefore calling delete on memory allocated by anything else other than new will result in bad things.

Furthermore the placement new may be called on any address, may not even be an allocated address. It can be called on an address located in the middle of some larger object, it may be called on a memory mapped region, it may be called on a raw virtual committed region, anything goes. delete woul attempt, in all these cases, to do what its implementation tell him to do: subtract the header size, interpret it as a new header, link it back into the heap. Kaboom.

The one that know how to release the memory of a placement new address is you, since you know exactly how was that memory allocated. delete will only do what it knows, and it may not be the right thing.

placement new and delete

The correct method is:

buf->~Buffer();
::operator delete(mem);

You can only delete with the delete operator what you received from the new operator. If you directly call the operator new function, you must also directly call the operator delete function, and must manually call the destructor as well.

Placement forms of the operator delete functions

If you don't want to use ::, you don't really have to. In fact, you generally shouldn't (don't want to).

You can provide replacements for ::operator new and ::operator delete (and the array variants, though you should never use them).

You can also, however, overload operator new and operator delete for a class (and yes, again, you can do the array variants, but still shouldn't ever use them).

Using something like void *x = ::operator new(some_size); forces the allocation to go directly to the global operator new instead of using a class specific one (if it exists). Generally, of course, you want to use the class specific one if it exists (and the global one if it doesn't). That's exactly what you get from using void *x = operator new(some_size); (i.e., no scope resolution operator).

As always, you need to ensure that your news and deletes match, so you should only use ::operator delete to delete the memory when/if you used ::operator new to allocate it. Most of the time you shouldn't use :: on either one.

The primary exception to that is when/if you're actually writing an operator new and operator delete for some class. These will typically call ::operator new to get a big chunk of memory, then divvy that up into object-sized pieces. To allocate that big chunk of memory, it typically (always?) has to explicitly specify ::operator new because otherwise it would end up calling itself to allocate it. Obviously, if it specifies ::operator new when it allocates the data, it also needs to specify ::operator delete to match.

Is calling delete on the result of a placement delete which used operator new okay?

delete p is equivalent to

p->~MyStruct();
operator delete(p);

unless MyStruct has an alternative operator delete, so your example should be well-defined with the expected semantics.

[expr.delete]/2 states:

the value of the operand of delete may be ... a pointer to a non-array object created by a previous new-expression.

Placement new is a type of new-expression. [expr.new]/1:

new-expression:

    ::opt new new-placementopt new-type-id new-initializeropt
    ::opt new new-placementopt ( type-id ) new-initializeropt

delete is defined to be a call to the destructor of the object and then a call to the deallocation function for the memory. [expr.delete]/6,7:

... the delete-expression will invoke the destructor (if any) for the object ...

... the delete-expression will call a deallocation function ...

As long as the deallocation function matches the allocation function (which it should, as long as you haven't overloaded operator delete for your class), then this should all be well defined.

how do you delete an object allocated with placement new

In the first case, there's no point in using placement new, since int doesn't have a constructor.

In the second case, it's either pointless (if myClass is trivial) or wrong, since there are already objects in the array.

You use placement new to initialise an object in a block of memory, which must be suitably aligned, and mustn't already contain a (non-trivial) object.

char memory[enough_bytes];  // WARNING: may not be properly aligned.
myClass * c = new (memory) myClass;

Once you've finished with it, you need to destroy the object by calling its destructor:

c->~myClass();

This separates the object's lifetime from that of its memory. You might also have to release the memory at some point, depending on how you allocated it; in this case, it's an automatic array, so it's automatically released when it goes out of scope.

operator delete throwing an exception with placement new

Problem here is use of the pointers.

This two lines are wrong:

simpleClass *simpleClassPtr_2 = new ((simpleClass*)ptrToMem + sizeof(simpleClass))simpleClass(2);
simpleClass *simpleClassPtr_3 = new ((simpleClass*)ptrToMem + sizeof(simpleClass)*2)simpleClass(3);

It should be like this:

simpleClass *simpleClassPtr_2 = new ((simpleClass*)ptrToMem + 1)simpleClass(2);
simpleClass *simpleClassPtr_3 = new ((simpleClass*)ptrToMem + 2)simpleClass(3);

Since pointer increase by one increases address by size of the pointed object so extra sizeof is not needed.
You were exceeding range of allocated memory size, so it ended with a crash.

Delete on placement new

Is the exception due to call of delete on a stack?

Yes. Though to clarify a little, this is not a C++ exception. It is an error that is detected by runtime. If runtime is not that smart, you could as well run into undefined behavior.

Is it fine to use placement new on memory block on stack?

Yes. You might also take a look at alloca() and Variable-length arrays (VLA) - those are another two mechanisms of allocating memory on stack. Note that VLA is part of C99 and not C++11 (and earlier) standards, but is supported by most production-grade compilers as an extension (it might appear in C++14).

If yes then how shall I delete the character pointer.

You should not. When you use a placement new, you do not call delete, you simply invoke a destructor. For any given object o of type T you need to call o->~T(); instead of delete o;. If you must, however, deal with the code that calls delete or delete [] on such an object, you might need to overload operators delete and delete[] and make those operators do nothing (destructor is already ran at that point).

Is it possible to assign multiple variables on a single block of memory using placement new?

Yes. However, you need to take extra care to make sure you meet alignment requirements.



Related Topics



Leave a reply



Submit