我可以对用new 分配的指针调用delete 吗?

问题描述 投票:0回答:5

我们可以在分配了

placement 
delete
 的指针上调用 
new
吗?如果没有那为什么?请详细解释一下。

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

delete
正在做两件事:

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

我认为删除没有理由无法对通过放置新创建的对象调用这两个操作中的任何一个。有知道原因吗?

c++ memory-management new-operator placement-new
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
only 释放之前由普通
new
分配的内存。通过放置
new
,您不必 必须使用正常
new
分配的内存,因此,由于正常
new
可能未分配内存,
delete
无法处理它。


5
投票

EDIT1:我知道没有放置删除。但我想知道为什么只是 删除操作者无法删除内存而不关心如何 指针所指的内存分配在哪里?

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

  • new
    必须与
    delete
  • 配对
  • new[]
    必须与
    delete[]
    配对(尽管大多数实现可以混合使用
    new
    new[]
  • malloc
    和炸薯条必须搭配
    free
  • CoTaskMemAlloc
    CoTaskMemFree
  • 配对
  • alloca
    不与任何东西配对(堆栈展开可以解决它)
  • MyCustomAllocator
    MyCustomFree
  • 配对

尝试调用错误的释放器将导致不可预测的行为(现在或以后很可能出现段错误)。因此,在除

delete
之外的其他内存分配的内存上调用
new
会导致不好的结果。

此外,新的放置可以在任何地址上调用,甚至可能不是分配的地址。它可以在位于某个较大对象中间的地址上调用,可以在内存映射区域上调用,也可以在原始虚拟提交区域上调用,一切都可以。在所有这些情况下,

delete
将尝试执行其实现告诉他要做的事情:减去标头大小,将其解释为
new
标头,将其链接回堆。轰隆隆。

知道如何释放新地址内存的人是you,因为你确切地知道该内存是如何分配的。

delete
只会做它知道的事情,而且可能不是正确的事情。


5
投票

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


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 operator 确实有一个相应的 delete operator,它被强制为精确的

void ::operator delete(void* [, size_t]) { }
,无操作;如果
T
的构造函数抛出异常,就会调用这个函数。


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.