我们可以在分配了展示位置delete
的指针上调用new
吗?如果没有那么为什么?请详细说明。
我知道没有展示位置删除。但我想知道为什么只删除opetator无法删除内存而不关心如何分配指针指向的内存?
delete
正在做两件事:
我认为没有删除的原因是不能在由placement new创建的对象上调用这两个操作中的任何一个。对原因有任何想法吗?
答案 0 :(得分:7)
您只能在使用delete
创建的指针上调用operator new
。如果您使用展示位置new
,其内存位置由普通operator new
分配,那么您可以安全地使用delete
(前提是您获得了正确的类型和指针)。但是,您可以在任何内存上使用放置new
,因此您通常会以其他方式管理该内存并手动调用该对象的析构函数。
例如,在这种错综复杂且通常不必要的情况下,delete
使用展示位置new
的内存是安全的,但这只是因为您之前使用new
分配了它: / p>
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
仅释放先前由普通new
分配的内存。对于展示位置new
,您不必须使用由普通new
分配的内存,因此可能无法通过普通new
分配,delete
无法处理它。
答案 1 :(得分:5)
不,因为删除不仅会调用析构函数,还会释放内存,但如果使用了placement new,则必须使用malloc()或stack自己分配内存。但是,您必须自己调用析构函数。另请参阅C++ FAQ。
答案 2 :(得分:4)
EDIT1:我知道没有展示位置删除。但我想知道为什么 删除操作员无法删除内存而不关心如何 指针指向哪个内存?
因为每种内存分配都使用一些特定于实现的内存跟踪(通常是在用户地址之前的标题块),这使得分配/释放仅在正确配对时才能工作:
new
必须与delete
new[]
必须与delete[]
配对(大多数实施,但原谅混合了new
和new[]
)malloc
和炒家必须与free
CoTaskMemAlloc
与CoTaskMemFree
alloca
对没有任何东西(堆栈展开处理它)MyCustomAllocator
与MyCustomFree
尝试调用错误的解除分配器将导致不可预测的行为(现在或之后很可能是段错误)。因此,对delete
以外的任何其他内容分配的内存调用new
将导致错误。
此外,可以在任何地址上调用placement new,甚至可能不是已分配的地址。它可以在位于某个较大对象中间的地址上调用,它可以在内存映射区域上调用,可以在原始虚拟已提交区域上调用,任何内容都可以。在所有这些情况下,delete
尝试执行其实现告诉他的操作:减去标头大小,将其解释为new
标头,将其链接回堆中。 KABOOM。
知道如何释放展示位置新地址内存的你,因为你确切知道该内存的分配方式。 delete
只会做它知道的事情,而且可能不是正确的事情。
答案 3 :(得分:0)
没有。 没有展示位置删除表达式。
典型情景:
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 运算符确实有一个相应的delete 运算符,它必须是void ::operator delete(void* [, size_t]) { }
,一个no-op;如果T
的构造函数抛出异常,则会调用此函数。
答案 4 :(得分:0)
不,因为新的展示位置不会分配任何内存。您在先前分配的原始内存上使用placement new。它唯一能做的就是调用对象的构造函数。