C++ 调用是否可以删除分配了新位置的指针?
我们可以在分配了位置C++ 调用是否可以删除分配了新位置的指针?,c++,memory-management,new-operator,placement-new,C++,Memory Management,New Operator,Placement New,我们可以在分配了位置new的指针上调用delete?如果没有,为什么?请详细解释 我知道没有位置删除。但是我想知道为什么仅仅删除Operator不能删除内存而不关心指针指向的内存是如何分配的 delete正在做两件事: 调用析构函数 释放内存 我看不出delete不能调用这两个操作中的任何一个的原因,这两个操作都是由placement new创建的。知道原因吗?没有。没有位置删除表达式 典型情况: void * const addr = ::operator new(sizeof(T)); /
new
的指针上调用delete
?如果没有,为什么?请详细解释
我知道没有位置删除。但是我想知道为什么仅仅删除Operator不能删除内存而不关心指针指向的内存是如何分配的
delete
正在做两件事:
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
的构造函数抛出异常,就会调用此函数。只能对使用运算符new创建的指针调用delete
。如果将placementnew
与普通运算符new
分配的内存位置一起使用,则可以安全地在其上使用delete
(前提是正确使用类型和指针)。但是,您可以在任何内存上使用placementnew
,因此您通常会以其他方式管理该内存,并手动调用对象的析构函数
例如,在这种复杂且通常不必要的情况下,可以安全地删除您在placementnew
上使用的内存,但这只是因为您在以下情况下使用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
仅释放以前由普通new
分配的内存。使用placementnew
,您不必使用由normalnew
分配的内存,因此由于normalnew
可能未分配内存,delete
无法处理该问题。否,因为delete不仅调用析构函数,还释放内存,但是如果使用placement new,则必须使用malloc()或stack自己分配内存。但是,您必须自己调用析构函数。另请参见。否,因为新位置不会分配任何内存。您可以在先前分配的原始内存上使用新位置。它所做的唯一事情就是调用对象的构造函数
编辑1:我知道没有位置删除。但我想知道为什么
删除Optator无法删除内存而不关心如何删除
分配指针指向的内存
因为每种类型的内存分配都使用一些特定于实现的内存跟踪(通常是位于用户地址之前的头块),这使得分配/解除分配只有在正确配对时才能工作:
new
必须与delete
new[]
必须与delete[]
配对(尽管大多数实现将new
和new[]
混合使用)
malloc
和frieds必须与free
CoTaskMemAlloc
与CoTaskMemFree
alloca
对空(堆栈展开处理)
MyCustomAllocator
与MyCustomFree
尝试调用错误的deallocator将导致不可预测的行为(很可能是现在或以后出现seg故障)。因此,对除new
以外的任何其他方法分配的内存调用delete
,将导致不好的结果
此外,新位置可以在任何地址上调用,甚至可能不是分配的地址。它可以调用位于某个较大对象中间的一个地址,它可以被调用在内存映射区域上,它可以在原始的虚拟提交区域上调用,任何东西都可以。code>delete
在所有这些情况下,我都会尝试执行其实现告诉他的操作:减去头大小,将其解释为new
头,将其链接回堆中。卡布姆
知道如何释放新地址的内存的人是你,因为你确切地知道内存是如何分配的<代码>删除
只会做它知道的事情,可能不是正确的事情。我知道没有位置删除,但是为什么只删除Operator不能删除内存而不关心指针指向的内存是如何分配的呢?@Narek因为delete
只释放new
分配的内存,但是通过placement new
,您可以使用普通new
未分配的内存,所以普通的delete
无法处理这个问题。普通的delete操作符只能删除普通的new操作符获得的内存。如您所见,这正是我在示例中使用它的方式。传递给placement new表达式以及placement new操作符的内存来自其他地方,与placement delete无关。仔细想想,placement delete运算符实际上是“释放”从placement new运算符获得的内存,即不做任何操作,这正是placement new运算符获取内存所做的。此外,请确保不要将分配/解除分配与构造/销毁混为一谈。前者是操作员的工作,后者是表达式的工作。由于没有placement delete表达式,您必须手动调用析构函数。为什么要从placement new开始?它满足了什么需求?实际上我来自于这个FAQ:)。有明文规定,您应该显式调用析构函数