在深入研究动态内存时,我发现琐碎类型如何开始其生命周期似乎是矛盾的。考虑片段
void* p = ::operator new(sizeof(int)); // 1
// 2
new (p) int; // 3
什么时候int
开始它的生命周期?
-
只获取存储,::operator new
被指定为具有效果(从[新.删除.单] https://timsong-cpp.github.io/cppwp/support.dynamic#new.delete.single-1)
new 表达式调用的分配函数来分配 size 字节的存储空间。 [...] 分配适当对齐的存储来表示该大小的任何对象,前提是该对象的类型没有新扩展对齐。
鉴于获取存储不够 https://stackoverflow.com/questions/40873520/reinterpret-cast-creating-a-trivially-default-constructible-object/40874245#40874245在创建对象时,int
它的生命周期不可能从这里开始。
此时,适合存储int
已被收购。
-
The int
是通过放置 new 创建的。但不知怎的,它的生命周期并不是从这里开始的,因为从[基本生活] https://timsong-cpp.github.io/cppwp/basic.life#1
[...] 如果一个对象属于类或聚合类型,并且该对象或其子对象之一是由普通默认构造函数以外的构造函数初始化的,则该对象被称为具有非空初始化。类型对象的生命周期T
开始于:
int
既不是类也不是聚合类型,因此它具有空初始化。因此只有第一条适用。然而,这显然不是获得存储的时间,因此也不可能是其生命周期开始的时间。
一些背景
分配器是必要的 https://timsong-cpp.github.io/cppwp/allocator.requirements#tab:utilities.allocator.requirements返回内存而不构造其元素。但这对于普通类型来说没有意义。的影响a.allocate(n)
with a
类型的分配器对象T
is
内存分配用于n
类型对象T
但对象并未被构造。
从技术上讲,新表达总是获得存储。代码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;
Returns: ptr.
Remarks:没有故意执行任何其他操作。
尽管“没有执行其他操作”,并且实现可能会优化任何实际的函数调用,但对分配函数的调用仍然算作为正在创建的对象获取存储空间。新表达.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)