代码之家  ›  专栏  ›  技术社区  ›  Passer By

由placement new创建的普通类型的生存期从什么时候开始?

  •  8
  • Passer By  · 技术社区  · 7 年前

    在深入研究动态记忆的过程中,我突然想到,琐碎的类型是如何开始其一生的,这似乎是矛盾的。考虑一下这个片段

    void* p = ::operator new(sizeof(int));  // 1
    // 2
    new (p) int; // 3
    

    什么时候 int 开始其生命周期?

    1. 仅获取存储, ::operator new 指定具有以下效果(从 [new.delete.single] )

      由新表达式调用的分配函数,用于分配大小字节的存储。[...] 分配适当对齐的存储以表示该大小的任何对象,前提是该对象的类型没有新的扩展对齐。

      考虑到获取存储 is insufficient 在创建对象时 内景 不可能在这里开始它的生命。

    2. 此时,为 内景 已被收购。

    3. 这个 内景 通过放置新建创建。但不知何故,它的生命并不是从这里开始的,因为 [basic.life]

      [...] 如果一个对象属于类或聚合类型,并且它或它的一个子对象是由一个构造函数(而不是一个普通的默认构造函数)初始化的,则称其具有非真空初始化。类型的对象的生存期 T 开始时间:

      • 存放时应保持适当的对齐和尺寸 T 获得,以及

      • 如果对象具有非真空初始化,则其初始化已完成[…]

      内景 既不是类也不是聚合类型,因此它的初始化是空的。因此,只有第一个项目符号适用。然而,这显然不是在获得存储的时候,因此不能是在其生存期开始的时候。

    一些上下文

    配置器 are required 返回内存而不构造其元素。然而,这对于琐碎的类型没有意义。的影响 a.allocate(n) 具有 a 类型的分配器对象 T

    内存分配给 n 类型的对象 T 但对象不是构造的。

    1 回复  |  直到 5 年前
        1
  •  7
  •   M.M    7 年前

    从技术上讲 新建表达式 始终获得存储。代码 new(p) int 两者都获得存储并创建一个对象,根据[基本生命]/1,对象的生命周期开始于 新建(p)int 获得存储。

    根据N4659[新增表达式],代码 新建(p)int 生成对分配函数的调用 ::operator new(sizeof(int), p) . 在[新建.删除.放置]下,标准库定义了这样一个函数:

    void* operator new(std::size_t size, void* ptr) noexcept;

    返回值: ptr。

    评论: 故意不执行其他操作。

    虽然“没有执行其他操作”,而且实现可能会优化任何实际的函数调用,但对分配函数的此调用仍算作为获取由创建的对象的存储 新建表达式 .

    推荐文章