是否可以在分配了新位置的指针上删除调用?

时间:2011-08-14 17:25:28

标签: c++ memory-management new-operator placement-new

我们可以在分配了展示位置delete 的指针上调用new吗?如果没有那么为什么?请详细说明。

我知道没有展示位置删除。但我想知道为什么只删除opetator无法删除内存而不关心如何分配指针指向的内存?

delete正在做两件事:

  1. 致电destrucor
  2. 释放记忆
  3. 我认为没有删除的原因是不能在由placement new创建的对象上调用这两个操作中的任何一个。对原因有任何想法吗?

5 个答案:

答案 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[]配对(大多数实施,但原谅混合了newnew[]
  • malloc和炒家必须与free
  • 配对
  • CoTaskMemAllocCoTaskMemFree
  • 配对
  • alloca对没有任何东西(堆栈展开处理它)
  • MyCustomAllocatorMyCustomFree
  • 配对

尝试调用错误的解除分配器将导致不可预测的行为(现在或之后很可能是段错误)。因此,对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。它唯一能做的就是调用对象的构造函数。