C ++删除,但不仅仅是类型

时间:2013-07-08 04:41:21

标签: c++ allocation placement-new delete-operator

假设我只想分配256字节的内存块

char * memory = new char[256];

比使用placement new创建一个FooBar对象(sizeof(Foobar)< = 256)

FooBar * obj = new (memory) FooBar();

确实

delete obj; //this also calls the destructor of FooBar

删除所有256字节的内存?

标准是否保证仅通过“删除obj”来释放整个“内存”缓冲区?或者它基于类型“FooBar”,因此此操作具有未定义的行为?

假设:FooBar是内存缓冲区中唯一的对象。

这不是重复的问题,请先了解问题。这个代码的作用并不是很明显。

2 个答案:

答案 0 :(得分:6)

C ++标准告诉您为什么未定义您正在做什么。 情况可能是由delete调用的释放使用已分配块的前置大小信息并正确释放它,但您不能依赖它。

§5.3.5删除

  

delete-expression运算符销毁由new-expression创建的派生程度最高的对象(1.8)或数组。   delete-expression:

     
      
  • :: delete cast-expression
  •   
  • :: delete [] cast-expression
  •   
     

第一种方法是非数组对象,第二种方法是数组。每当delete关键字后面紧跟空方括号时,它应被解释为第二种选择。 [...]

要说的是,现在我们来到更有趣的部分:

  

2 [...]在第一个替代(删除对象)中,delete的操作数的值可以是空指针值,指向由前一个new-expression创建的非数组对象的指针,或者指向表示这种对象的基类的子对象(1.8)的指针(第10条)。 如果不是,则行为未定义。 [...]

  1. 指向对象的指针不是由新表达式创建的,而是仅通过放置new来完成对象构造。
  2. 地址obj上的指针(应转换为void*与投放到memory的{​​{1}}相同,但是你甚至不能依赖它)点数是使用void*分配的,因此必须使用new[]
  3. 查看相关问题:


    如果您想为多个相同类型的对象预先分配存储空间: 考虑使用delete[]

    然后,

    std::vector<FooBar>::reserve()emplace_back()将执行对象的就地构造。

答案 1 :(得分:5)

这确实是未定义的行为,正确的做法是明确地调用该内存块中分配的每个对象的析构函数,然后释放内存块本身。

obj->~FooBar();
delete[] memory;

请记住,placement new只是构造对象,它不会分配内存,所以对象不应该释放它。如果你分配内存,你应该释放它,如果你构造了对象,你应该只解构它。