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 withdelete
new[]
must pair withdelete[]
(most implementations though forgive mixing thenew
andnew[]
)malloc
and frieds must pair withfree
CoTaskMemAlloc
pairs withCoTaskMemFree
alloca
pairs with nothing (stack unwinding takes care of it)MyCustomAllocator
pairs withMyCustomFree
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 new
s and delete
s 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
Why Is Iterating 2D Array Row Major Faster Than Column Major
Getting the Size of a C++ Function
How to Read Frames from Videocapture from Secondary Webcam with Opencv
How to Save Hicon to an .Ico File
Where Should Non-Member Operator Overloads Be Placed
Why Can't I Use a "Break" Statement Inside a Ternary Conditional Statement in C++
Is It More Efficient to Copy a Vector by Reserving and Copying, or by Creating and Swapping
Difference Between Steady_Clock VS System_Clock
Overload Resolution with Std::Function
C++ Static_Cast Runtime Overhead
How to Not Wait for a System() Command to Finish? (In C)
How to Make a C++ Struct Value-Initialize All Pod Member Variables
Overload Resolution: Assignment of Empty Braces
Why Are the Return Values of These Doubles -1.#Ind
Referencing Memory Operands in .Intel_Syntax Gnu C Inline Assembly