【问题标题】:At what point does the lifetime of a trivial type created by placement-new start?由placement-new 创建的普通类型的生命周期从什么时候开始?
【发布时间】:2018-08-08 20:17:42
【问题描述】:

在深入研究动态内存的过程中,我突然想到,琐碎的类型如何开始它们的生命周期似乎是矛盾的。考虑sn-p

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

int 的生命周期何时开始?

  1. 只获取存储,指定::operator new有效果(来自[new.delete.single]

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

    鉴于在创建对象时获取存储空间is insufficientint 不能在此处开始其生命周期。

  2. 此时,int 的合适存储空间已获得。

  3. int 是由放置 new 创建的。但不知何故,它的生命周期并没有从这里开始,因为从 [basic.life]

    [...] 如果一个对象是一个类或聚合类型,并且它或它的一个子对象由一个普通的默认构造函数以外的构造函数初始化,则称它具有非空初始化。 T 类型对象的生命周期开始于:

    • 获得了与T类型正确对齐和大小的存储,并且

    • 如果对象有非空初始化,则其初始化完成[...]

    int 既不是类也不是聚合类型,因此它的初始化是空的。因此只有第一个项目符号适用。但是,这显然不是获得存储的时间,因此不可能是其生命周期开始的时间。

一些上下文

分配器are required 在不构造其元素的情况下返回内存。然而,这对于平凡的类型没有意义。 a.allocate(n)a 类型 T 的分配器对象的效果是

T 类型的n 对象分配了内存,但未构造对象。

【问题讨论】:

  • 相关“constructing” a trivially-copyable object with memcpyseveral linked questions 涵盖了这个主题的几个变体,其中一个几乎肯定会涵盖这个案例。
  • 相关的是 P0593(最近更新了修订版 2),尽管到目前为止还没有提出对标准的具体更改
  • 这不是其他线程的欺骗(placement-new 与memcpy 或其他线程有很大不同)。该线程的原始标题对其提出的真正问题具有误导性
  • @M.M:但是the answer is the same。根据 [intro.object]/1,放置 new 是导致创建对象的原因。你不能开始一个不存在的对象的生命周期。
  • @NicolBolas 您链接的答案中没有任何内容适用于这个问题。在这个问题的代码中有 is 一个由placement-new创建的对象;该答案(以及它所回答的问题)是关于没有创建对象的情况

标签: c++ language-lawyer object-lifetime placement-new object-model


【解决方案1】:

从技术上讲,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 正在创建的对象获取存储空间 em>。

【讨论】:

  • 这出乎意料。我喜欢标准如何知道这看起来完全是假的,但是否可以使语言保持一致
  • @PasserBy 如果 [basic.life]/1 在此答案中由 [intro.object]/1 完成,则标准似乎更加一致:[...]创建了一个对象通过定义、新表达式、隐式更改联合的活动成员或创建临时对象时
  • @Oliv 什么时候执行定义?
  • @curiousguy 这是一个陷阱,不是吗?我认为在 C++20 之前是放置分配函数返回的时候。但是现在,已经完成了 int 的空初始化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-18
  • 2021-08-31
  • 2010-12-08
  • 1970-01-01
相关资源
最近更新 更多