何时定位新定义好,以及在调用放置新内容时现有类型会发生什么?

时间:2014-11-27 17:13:37

标签: c++ language-lawyer placement-new

我已经看到了一些新的放置示例,并且对于内部发生的各种类型的内容感到有些困惑。

一个简单的例子:

using my_type       = std::string;
using buffer_type   = char;

buffer_type  buffer[1000];
my_type*     p{ new (buffer) my_type() };

p->~my_type();

据我所知,这是有效的,尽管我关心buffer[]的char数组会发生什么。只要在内存中创建新对象后我没有以任何形式访问变量buffer,这似乎就可以了。

为了保持这个简单,我不关心在这里做正确对齐的任何事情,或者在调用放置新内容时可能出错的任何其他主题除了:原始类型会发生什么?我可以使用其他类型如buffer_type = int来实现类似的效果(忽略实际需要多少内存的可能性)?任何POD都安全buffer_type吗?非POD类型怎么样?我是否必须告诉编译器char数组在某种程度上不再有效? my_type可能存在或不存在的限制是什么?

这段代码是否符合我的预期,是否定义明确,是否有任何微小的修改可以保持定义或将其分解为未定义的行为?

2 个答案:

答案 0 :(得分:3)

  

原始类型会发生什么?

你的意思是原始物体?它会被摧毁,也就是说它的生命终结。只要重用其存储,类型buffer_type [1000]的数组对象的生命周期就会结束。

  

程序可以通过重用存储来结束任何对象的生命周期   对象占用或显式调用析构函数   具有非平凡析构函数的类类型的对象。对于一个对象   对于具有非平凡析构函数的类类型,程序不是   需要在存储之前显式调用析构函数   对象占用被重用或释放;但是,如果没有   显式调用析构函数或者如果是delete-expression(5.3.5)   不习惯释放存储,析构函数不得   隐式调用以及任何依赖于副作用的程序   由析构函数生成的行为具有不确定的行为。

请注意,这意味着我们不应该对缓冲区使用非平凡的析构函数:元素'析构函数在它定义的范围的末尾被调用。例如std::string作为元素类型,暗示对不存在的数组子对象进行析构函数调用,这显然会触发未定义的行为。

  

如果某个程序使用[...]结束T类型对象的生命周期   自动(3.7.3)存储持续时间以及T是否具有非平凡性   析构函数,程序必须保证原始对象   类型在隐式析构函数时占用相同的存储位置   电话会议;否则程序的行为是不确定的。

为了避免在你完成它之后你必须将std:string构建到缓冲区中,这看起来真的是荒谬的。

  

POD是否安全为buffer_type

我们不一定需要POD - 它们有很多要求,这些都不是必需的。 困扰我们的唯一事情是构造函数和析构函数。
重要的是类型析构函数是微不足道的(或者对于数组,数组元素类型'析构函数)。同样可行的是,构造函数也是微不足道的。

POD类型感觉更安全,因为它们满足两个要求并传达了“裸存储”的想法。很好。

  

my_type可能存在或不存在的限制是什么?

是。它应该是一个对象类型。它可以是任何对象类型,但它不能作为参考。

答案 1 :(得分:1)

任何POD类型都是安全的。另外,虽然有点危险,但我相信析构函数为空的大多数非POD类型也可以在这里工作。如果析构函数不为空,则会在buffer上调用它并尝试访问其不再有效的数据(由于新的展示位置)。