简体   繁体   中英

Confusion about deleting objects created via placement new

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM