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
正在做两件事:

  • 调用析构函数
  • 释放内存
  • 我看不出delete不能调用这两个操作中的任何一个的原因,这两个操作都是由placement new创建的。知道原因吗?

    没有。没有位置删除表达式

    典型情况:

    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
    。如果将placement
    new
    与普通
    运算符new
    分配的内存位置一起使用,则可以安全地在其上使用
    delete
    (前提是正确使用类型和指针)。但是,您可以在任何内存上使用placement
    new
    ,因此您通常会以其他方式管理该内存,并手动调用对象的析构函数

    例如,在这种复杂且通常不必要的情况下,可以安全地
    删除您在placement
    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
    释放以前由普通
    new
    分配的内存。使用placement
    new
    ,您不必使用由normal
    new
    分配的内存,因此由于normal
    new
    可能未分配内存,
    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:)。有明文规定,您应该显式调用析构函数