【问题标题】:Can you / how can you reallocate C++ objects created with placement new?你能/你如何重新分配使用新位置创建的 C++ 对象?
【发布时间】:2011-09-05 21:49:33
【问题描述】:

我有一个 C++ 对象,该对象是在主机应用程序提供的内存缓冲区中的插件中创建的,使用placement new 运算符,其方式类似于以下代码:

MyClass* createObject(void* inNewBlock)
{
  MyClass* elementAddr = static_cast<MyClass*>(inNewBlock);
  new (elementAddr) MyClass(); // Placement new into pre-allocated memory
}

我知道我不能删除以这种方式创建的对象,但我想知道是否有办法清空内存并在以后需要时重新分配对象:

void removeObject(MyClass* object)
  memset(object, NULL, sizeof(MyClass));
}

void restoreObject(MyClass* object)
{
  new (object) MyClass(); // Placement new into pre-allocated memory
}

上面的代码不起作用。我试过了,当我调用restoreObject() 时,主机应用程序挂起或崩溃。我希望有人可以向我解释为什么这不起作用以及可能的替代方法。

【问题讨论】:

  • 你能得到堆栈跟踪吗?可能对象指向的内存不够大。
  • 您能解释一下“稍后重新分配 对象”是什么意思吗?

标签: c++ memory-management


【解决方案1】:

这太令人费解了。当您不再需要它时,您可以简单地销毁该对象。此外,placement-new 参数已经是一个 void 指针,无需强制转换。这与标准库分配器所做的非常相似:

MyClass * create(void * addr)
{
  return ::new (addr) MyClass;    // default-initialize
}
MyClass * create(void * addr, const MyClass & x)
{
  return ::new (addr) MyClass(x); // copy-construct from prototype
}

void destroy(MyClass * p)
{
  p->~MyClass();   // you can now reuse the memory
}

没有所谓的“恢复”;如果您已正确销毁该对象,则可以在内存中创建一个新对象,该对象以前由另一个对象使用。

编辑:我添加了另一个构造方法,它可以复制给定对象,以防你的类不是默认可构造的。

【讨论】:

    【解决方案2】:

    在将该内存设置为 0 之前,您需要调用对象的析构函数。例如:

    void removeObject(MyClass* object)
    {
      object->~MyObject();
      memset(object, NULL, sizeof(MyClass);
    }
    

    否则对象不会释放其资源。

    除此之外,您所做的事情本身并没有错。如果它在以上述方式修改它后崩溃,它是宿主应用程序存储了与每个对象不兼容的东西并试图将它与不同的对象一起使用。您必须展示它在主机应用程序中的使用方式。

    【讨论】:

      【解决方案3】:

      如果使用placement new,则必须直接调用析构函数:

      MyClass* elementAddr = new (inNewBlock) MyClass();
      //Do stuff
      elementAddr->~MyClass();
      //inNewBlock is now free to be used for other purposes.
      

      【讨论】:

        【解决方案4】:

        我强烈建议您传递内存缓冲区的大小,以防止发生坏事。

        还要注意放置 new 的一个大陷阱:内存对齐。见placement new + array +alignment

        传入一个超大的缓冲区会有所帮助。

        MyClass* createObject(void* inNewBlock, size_t size)
        {
          // basic sanity check
          assert(size >= sizeof(MyClass);
        
          MyClass* result = new (inNewBlock) MyClass(); 
        
          // result might not be the same as elementAddr
          // check that the result fits in-to the space provided.       
          assert(result + sizeof(MyClass) <= (char*)inNewblock + size);
          return result;
        }
        

        我知道我无法删除以这种方式创建的对象

        其实你可以(如其他答案所示):

        void deleteObject(MyClass* c) 
        {
           c->~MyClass();
        }
        
        MyClass* restoreObject(MyClass* c)
        {
           return createObject(c, sizeof(MyClass));
        }
        

        【讨论】:

          猜你喜欢
          • 2020-12-17
          • 1970-01-01
          • 1970-01-01
          • 2010-09-05
          • 2014-02-28
          • 1970-01-01
          • 2014-07-28
          相关资源
          最近更新 更多