我已经看到了一些新的放置示例,并且对于内部发生的各种类型的内容感到有些困惑。
一个简单的例子:
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
可能存在或不存在的限制是什么?
这段代码是否符合我的预期,是否定义明确,是否有任何微小的修改可以保持定义或将其分解为未定义的行为?
答案 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
上调用它并尝试访问其不再有效的数据(由于新的展示位置)。