5

我们可以调用与放置delete一起分配的指针吗?如果没有,那为什么?请详细说明。new

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

delete正在做两件事:

  1. 调用析构函数
  2. 释放内存

而且我认为删除没有理由不能对放置 new 创建的对象调用这两个操作中的任何一个。关于原因的任何想法?

4

5 回答 5

7

您只能调用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 释放以前由 normal 分配的内存new。使用placement new,您不必使用由 normal 分配的内存new,因此在没有被 normal 分配的可能性的情况下newdelete无法处理它。

于 2011-08-14T17:30:11.370 回答
5

EDIT1:我知道没有放置删除。但我想知道为什么只是删除操作符不能删除内存而不关心指针指向的内存是如何分配的?

因为每种类型的内存分配都使用一些特定于实现的内存跟踪(通常是用户地址之前的头块),这使得分配/解除分配只有在正确配对时才能工作:

  • new必须搭配delete
  • new[]必须配对delete[](大多数实现虽然原谅混合newand new[]
  • malloc炸薯条必须搭配free
  • CoTaskMemAllocCoTaskMemFree
  • alloca没有任何东西的配对(堆栈展开处理它)
  • MyCustomAllocatorMyCustomFree

尝试调用错误的释放器将导致不可预测的行为(现在或以后很可能出现段错误)。因此,调用delete由其他任何东西分配的内存new会导致不好的事情。

此外,放置 new 可以在任何地址上调用,甚至可能不是分配的地址。它可以在位于某个较大对象中间的地址上调用,可以在内存映射区域上调用,也可以在原始虚拟提交区域上调用,任何事情都可以。delete在所有这些情况下,将尝试执行其实现告诉他做的事情:减去标头大小,将其解释为new标头,将其链接回堆。卡布姆。

知道如何释放放置新地址的内存的是,因为您确切知道该内存是如何分配的。delete只会做它知道的事情,而且可能不是正确的事情。

于 2011-08-14T21:48:08.693 回答
5

不,因为 delete 不仅调用析构函数而且释放内存,但如果你使用placement new,你必须自己使用malloc() 或堆栈分配内存。但是,您必须自己调用析构函数。另请参阅C++ 常见问题解答

于 2011-08-14T17:30:43.997 回答
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操作符确实有一个相应的删除操作符,该操作符被要求精确void ::operator delete(void* [, size_t]) { }为无操作;如果 的构造函数T抛出异常,就会调用 this 。

于 2011-08-14T17:28:48.237 回答
0

不,因为放置 new 不会分配任何内存。您在先前分配的原始内存上使用新位置。它唯一做的就是调用对象的构造函数。

于 2011-08-14T17:31:02.780 回答