I am not absolutely sure what is happening in the code below:
#include <iostream>
struct Foo
{
double dummy{42};
static void* operator new(std::size_t size, void* p)
{
std::cout << R"(Calling placement "operator new" for size )"
<< size << '\n';
return ::operator new(size, p);
}
Foo()
{
std::cout << "Foo::Foo()" << std::endl;
}
~Foo()
{
std::cout << "~Foo::Foo()" << std::endl;
}
};
int main()
{
void* buf_heap = new char[128] {};
Foo* pFoo_heap = new(buf_heap) Foo; // placement allocation
// why does this line call the correct operator delete?
delete pFoo_heap;
// the line above seems to be equivalent to:
// pFoo_heap->~Foo();
// ::operator delete(buf_heap);
}
I know that whenever one uses placement new
when constructing an object, the destructor should be manually called, followed by a call to release the memory (usually via ::operator delete
or ::operator delete[]
, or free
, depending on how placement new
is implemented), see eg How to delete object constructed via placement new operator?
However, in my code above, I created a Foo
object which I placed in heap-allocated memory. Then, when I call delete pFoo_heap
, the destructor is automatically invoked (this I understand), however it seems also that the memory is also released ( buf_heap
in this case). That is, if I try after to do ::operator delete[](buf_heap);
I'm getting a segfault.
So basically the line
delete pFoo_heap;
seems to be equivalent to
pFoo_heap->~Foo();
::operator delete[](buf_heap);
Is this indeed the case (or it is just UB)? Why is the memory allocated in buf_heap
de-allocated? Or, in other words, does delete pFoo_heap;
know where the memory came from, even if allocated via a placement new
?
You asked:
// why does this line call the correct operator delete?
delete pFoo_heap;
// the line above seems to be equivalent to:
// pFoo_heap->~Foo();
// ::operator delete(buf_heap);
That is not true. Your code is subject to undefined behavior. From the C++ Standard:
5.3.5 Delete
2 If the operand has a class type, the operand is converted to a pointer type by calling the above-mentioned conversion function, and the converted operand is used in place of the original operand for the remainder of this section. In the first alternative ( delete object ), the value of the operand of
delete
may be a null pointer value, a pointer to a non-array object created by a previous new-expression , or a pointer to a subobject (1.8) representing a base class of such an object (Clause 10). If not, the behavior is undefined.
In your case, pFoo_heap
was not created by a new-expression , buf_heap
was created by a new-expression . You need to use:
pFoo_heap->~Foo();
delete [] buf_heap;
for a well behaved program.
Why is the memory allocated in
buf_heap
de-allocated?
Because you're de-allocating it. Note that buf_heap == pFoo_heap
, so when you do delete pFoo_heap
that happens to work exactly as if you had done new Foo
to begin with - the pointer you're deleting is pointing to memory that was previously allocated with new
. So it... "works"...
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.