在潜入动态记忆的过程中,我发现看起来矛盾的是琐碎的类型如何开始它们的生命。考虑一下代码段
New-SelfSignedCertificate
void* p = ::operator new(sizeof(int)); // 1
// 2
new (p) int; // 3
何时开始生命?
仅获取存储空间,int
被指定具有效果(来自[new.delete.single])
new-expression调用的分配函数用于分配大小的存储字节。 [...]分配适当对齐的存储空间以表示该对象的任何对象,前提是对象的类型没有新的扩展对齐。
鉴于在创建对象时获取存储is insufficient,::operator new
无法在此处开始其生命周期。
此时,已获取int
的合适存储空间。
int
是由展示位置新建的。但不知何故,从[basic.life]
[...]如果一个对象属于类或聚合类型,并且它或其子对象之一由除了普通默认构造函数之外的构造函数初始化,则称该对象具有非空的初始化。类型为
int
的对象的生命周期始于:
获取具有
T
类型的正确对齐和大小的存储,如果对象具有非空的初始化,则其初始化完成[...]
T
既不是类也不是聚合类型,因此它具有空的初始化。因此,只有第一颗子弹适用。但是,这显然不是在获得存储时,因此不能在其生命周期开始时使用。
分配器are required返回内存而不构造其元素。然而,对于琐碎的类型来说,这是没有意义的。 int
与a.allocate(n)
类型a
的分配器对象的影响是
为
T
类型的n
对象分配内存,但不构造对象。
答案 0 :(得分:7)
从技术上讲, new-expression 总是获得存储空间。代码new(p) int
都获得存储并创建一个对象,根据[basic.life] / 1,对象的生命周期在new(p) int
获得存储时开始。
根据N4659 [expr.new],代码new(p) int
生成对分配函数::operator new(sizeof(int), p)
的调用。在[new.delete.placement]下,标准库定义了这样一个函数:
void* operator new(std::size_t size, void* ptr) noexcept;
返回: ptr。
备注:故意不执行任何其他操作。
虽然"没有其他行动"执行,并且可能实现将优化任何实际的函数调用,这种对分配函数的调用仍然计为获取由 new-expression 创建的对象的存储。