我不完全确定以下代码中发生了什么:
#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);
}
我知道无论何时在构造对象时使用展示位置new
,都应手动调用析构函数,然后调用释放内存(通常通过::operator delete
或::operator delete[]
,或free
,具体取决于展示new
的展示位置),请参阅例如How to delete object constructed via placement new operator?
但是,在上面的代码中,我创建了一个Foo
对象,我将其放在堆分配的内存中。然后,当我调用delete pFoo_heap
时,会自动调用析构函数(我理解这一点),但似乎内存也被释放(在这种情况下为buf_heap
)。也就是说,如果我尝试::operator delete[](buf_heap);
我会遇到段错误。
基本上就是
行delete pFoo_heap;
似乎等同于
pFoo_heap->~Foo();
::operator delete[](buf_heap);
确实如此(或者只是UB)?为什么在buf_heap
中分配的内存被解除分配?或者换句话说,即使通过展示位置delete pFoo_heap;
分配,new
也知道内存的来源吗?
答案 0 :(得分:3)
你问:
// 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);
事实并非如此。您的代码受到未定义的行为的影响。来自C ++标准:
5.3.5删除
2如果操作数具有类类型,则通过调用上述转换函数将操作数转换为指针类型,并使用转换后的操作数代替本节其余部分的原始操作数。在第一个替代方法(删除对象)中,
delete
的操作数的值可以是空指针值,指向由前一个 new创建的非数组对象的指针-expression ,或指向表示此类对象的基类的子对象(1.8)的指针(第10条)。如果不是,则行为未定义。
在您的情况下,pFoo_heap
不是由 new-expression 创建的,buf_heap
是由 new-expression 创建的。你需要使用:
pFoo_heap->~Foo();
delete [] buf_heap;
表现良好的节目。
答案 1 :(得分:1)
为什么在
buf_heap
中分配的内存被解除分配?
因为你要取消分配它。请注意buf_heap == pFoo_heap
,因此当您执行的delete pFoo_heap
恰好就像您开始使用new Foo
时一样 - 您要删除的指针指向之前已分配的内存与new
。所以它......“有效”......