我们可以在分配了
placement
delete
的指针上调用
new
吗?如果没有那为什么?请详细解释一下。
我知道没有展示位置删除。但我想知道为什么只是删除操作者不能删除内存而不关心指针指向的内存是如何分配的?
delete
正在做两件事:
我认为删除没有理由无法对通过放置新创建的对象调用这两个操作中的任何一个。有知道原因吗?
您只能对使用
delete
创建的指针调用 operator new
。如果您将放置 new
与由普通 operator new
分配的内存位置一起使用,那么您可以安全地在其上使用 delete
(前提是您获得了正确的类型和指针)。但是,您可以在任何内存上使用放置new
,因此您通常会以其他方式管理该内存并手动调用对象的析构函数。
例如,在这种复杂且通常不必要的场景中,
delete
您使用放置new
的内存是安全的,但这只是因为您之前使用new
分配了它:
char* mem = new char[sizeof(MyObject)];
MyObject* o = new (mem) MyObject;
// use o
o->~MyObject(); // with placement new you have to call the destructor by yourself
delete[] mem;
但是,这是非法的:
char mem[16]; // create a buffer on the stack, assume sizeof(MyObject) == 16
MyObject* o = new (mem) MyObject; // use stack memory to hold a MyObject
// note that after placement new is done, o == mem
// pretend for this example that the point brought up by Martin in the comments didn't matter
delete o; // you just deleted memory in the stack! This is very bad
另一种思考方式是
delete
only 释放之前由普通 new
分配的内存。通过放置 new
,您不必 必须使用正常 new
分配的内存,因此,由于正常 new
可能未分配内存,delete
无法处理它。
EDIT1:我知道没有放置删除。但我想知道为什么只是 删除操作者无法删除内存而不关心如何 指针所指的内存分配在哪里?
因为每种类型的内存分配都使用一些特定于实现的内存跟踪(通常是用户地址之前的标头块),这使得分配/释放只有在正确配对时才能工作:
new
必须与 delete
new[]
必须与 delete[]
配对(尽管大多数实现可以混合使用 new
和 new[]
)malloc
和炸薯条必须搭配 free
CoTaskMemAlloc
与 CoTaskMemFree
alloca
不与任何东西配对(堆栈展开可以解决它)MyCustomAllocator
与 MyCustomFree
尝试调用错误的释放器将导致不可预测的行为(现在或以后很可能出现段错误)。因此,在除
delete
之外的其他内存分配的内存上调用 new
会导致不好的结果。
此外,新的放置可以在任何地址上调用,甚至可能不是分配的地址。它可以在位于某个较大对象中间的地址上调用,可以在内存映射区域上调用,也可以在原始虚拟提交区域上调用,一切都可以。在所有这些情况下,
delete
将尝试执行其实现告诉他要做的事情:减去标头大小,将其解释为new
标头,将其链接回堆。轰隆隆。
知道如何释放新地址内存的人是you,因为你确切地知道该内存是如何分配的。
delete
只会做它知道的事情,而且可能不是正确的事情。
不可以,因为delete不仅调用析构函数,而且还释放内存,但如果你使用placement new,你必须自己使用malloc()或stack分配内存。但是,您必须自己调用析构函数。另请参阅 C++ 常见问题解答。
不。 没有放置删除表达式。
典型场景:
void * const addr = ::operator new(sizeof(T)); // get some memory
try {
T * const pT = new (addr) T(args...); // construct
/* ... */
p->~T(); // nap time
}
catch (...) {
}
::operator delete(addr); // deallocate
// this is _operator_-delete, not a delete _expression_
请注意,placement-new operator 确实有一个相应的 delete operator,它被强制为精确的
void ::operator delete(void* [, size_t]) { }
,无操作;如果 T
的构造函数抛出异常,就会调用这个函数。
不,因为新的放置不会分配任何内存。您可以在先前分配的原始内存上使用新的放置。它唯一做的就是调用对象的构造函数。