你能/你如何重新分配使用placement new创建的C ++对象?

时间:2011-09-05 21:49:34

标签: c++ memory-management

我有一个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()时,主机应用程序挂起或崩溃。我希望有人可以向我解释为什么这不起作用以及可能的替代方案。

4 个答案:

答案 0 :(得分:7)

这太复杂了。当你不再需要它时,你可以简单地销毁它。另外,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
}

没有“恢复”这样的东西;你可以在内存中创建一个新对象,如果你已经正确地销毁了那个对象,那么该对象将被另一个对象使用。

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

答案 1 :(得分:4)

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

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

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

除此之外,你正在做的事情本身没有任何错误。如果在以上述方式修改它之后崩溃,则主机应用程序存储与每个对象不兼容的东西,并尝试将其与不同的对象一起使用。您必须显示它在主机应用程序中的使用方式。

答案 2 :(得分:2)

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

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

答案 3 :(得分:0)

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

还要注意放置新内容的一个重大缺陷:内存对齐。请参阅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));
}