假设我只想分配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是内存缓冲区中唯一的对象。
这不是重复的问题,请先了解问题。这个代码的作用并不是很明显。
答案 0 :(得分:6)
C ++标准告诉您为什么未定义您正在做什么。
情况可能是由delete
调用的释放使用已分配块的前置大小信息并正确释放它,但您不能依赖它。
delete-expression运算符销毁由new-expression创建的派生程度最高的对象(1.8)或数组。 delete-expression:
- :: delete cast-expression
- :: delete [] cast-expression
第一种方法是非数组对象,第二种方法是数组。每当delete关键字后面紧跟空方括号时,它应被解释为第二种选择。 [...]
要说的是,现在我们来到更有趣的部分:
2 [...]在第一个替代(删除对象)中,delete的操作数的值可以是空指针值,指向由前一个new-expression创建的非数组对象的指针,或者指向表示这种对象的基类的子对象(1.8)的指针(第10条)。 如果不是,则行为未定义。 [...]
obj
上的指针(应转换为void*
与投放到memory
的{{1}}相同,但是你甚至不能依赖它)点数是使用void*
分配的,因此必须使用new[]
。查看相关问题:
如果您想为多个相同类型的对象预先分配存储空间:
考虑使用delete[]
。
std::vector<FooBar>::reserve()
或emplace_back()
将执行对象的就地构造。
答案 1 :(得分:5)
这确实是未定义的行为,正确的做法是明确地调用该内存块中分配的每个对象的析构函数,然后释放内存块本身。
obj->~FooBar();
delete[] memory;
请记住,placement new只是构造对象,它不会分配内存,所以对象不应该释放它。如果你分配内存,你应该释放它,如果你构造了对象,你应该只解构它。