空虚初始化的对象的生存期

时间:2018-09-03 18:30:29

标签: c++ language-lawyer c++17 object-lifetime

当前的标准草案在[basic.life/1]中说(以前的标准措辞类似):

  

对象或引用的生存期是   对象或参考。据说一个物体是非空的   初始化,如果它是类或聚合类型,并且它是以下之一   它的子对象是由琐碎的构造函数初始化的   默认构造函数。 [注意:通过简单的复制/移动进行初始化   构造函数是非空初始化。 —尾注]一生   类型T的对象的开始时间是:

     

(1.1)正确存储   获得了T型的对齐方式和大小,并且

     

(1.2)如果对象具有   非空初始化,其初始化完成,

查看此代码:

alignas(int) char obj[sizeof(int)];

basic.life/1是否意味着int(以及其他几种与int具有相同或更少对齐/尺寸要求的类型)已经开始使用?

这甚至意味着什么?如果对象已开始其生存期,则创建它吗? [intro.object/1]说:

  

[...]当隐式更改联合的活动成员([class.union])或临时对象时,将通过定义([basic.def]),new-expression创建对象。对象已创建([conv.rval],[class.temporary])[...]

因此,因此,不会创建我的obj(作为int)。但是它作为int(以及其他可能无限类型的能空初始化的对象)的生命已经开始。

我很困惑,你能澄清一下吗?

3 个答案:

答案 0 :(得分:8)

除非已创建,否则无法开始对象的生存期。 [intro.object] / 1定义了创建对象的唯一方法:

  

在隐式更改联合的活动成员(12.3)或创建临时对象(7.4、15.2)时,将通过定义(6.1),新表达式(8.3.4)创建对象。

此定义创建的对象的类型为char[]。因此,这是生命周期开始的唯一对象。并且此构造不会创建其他对象。

为了使这种解释可信,存在C ++ 20 P0593的提案,其主要目的是 该声明可以隐式创建其他此类对象。


评论:

  

(1.2)中的条件仍然困扰着我。为什么在那儿?

之所以存在,是因为它无法为未初始化的对象说“初始化完成”。

  

假设我之后有一个new(obj) int。显然可以创建一个int对象。但是在此之前,obj已经获得了必要的存储空间。

否,obj的声明为类型char[]的对象获得了存储。为正在创建的int对象获取存储空间的是new(obj)。是的,placement-new表达式可为其创建的对象获取存储空间。就像声明变量一样,它为创建的对象获取存储空间。

仅仅因为该存储已经存在并不意味着它不会被获取。

答案 1 :(得分:5)

我翻译

  

类型为T的对象的生存期开始于...

表示

  

鉴于程序创建了一个T对象,下面将描述该对象的生命周期何时开始...

不是

  

如果满足以下条件,则类型为T的对象存在,并且其生存期开始于...

也就是说,存在一个隐含的附加条件,即以[intro.object] / 1中描述的某种方式“创建”对象。但是[basic.life] 1 /段落本身并不意味着任何对象都存在,只有存在的对象的属性之一。

因此,对于您的声明,文本描述了char[sizeof(int)]类型的一个对象和char类型的一个或多个对象的生存期开始(即使声明是在块范围内的语句)并且没有初始化),但是由于没有隐式存在的类型int的对象,因此我们将不对此类对象的寿命进行任何说明。

答案 2 :(得分:0)

由于该标准刻意避免要求所有实现都适合于所有目的,因此对于出于各种目的而设计的高质量实现而言,经常有必要保证标准本身不对其施加任何要求的代码的行为。

如果某个类型T支持隐式对象创建,并且程序将某个对象的地址转换为T*,则该高质量实现旨在支持低级编程概念而无需特殊操作语法的行为就好像这种转换在允许程序具有已定义行为的情况下创建类型为T的对象,但在不需要这样做但会导致结果的情况下,则不会隐式创建此类对象通过破坏其他对象而处于未定义行为中。

因此,如果floatuint32_t的大小相同且具有相同的对齐要求,则给出例如

alignas(uint32_t) char obj[sizeof(uint32_t)];

float *fp = (float*)obj;
*fp = 1.0f;
uint32_t *up = (uint32_t*)obj;

fp的初始化将创建一个float,因为需要进行对*fp的分配。如果up的使用方式要求在那里存在uint32_t,则对up的分配可以在销毁那里的float的同时创建一个。如果未以这种方式使用up,而是以fp仍然存在的方式使用float,则float仍然存在。如果两个指针的使用都要求各个对象仍然存在,那么即使是用于低级编程的高质量编译器也可能无法处理这种可能性。

请注意,并非特别适合于低级编程的实现可能不支持此处描述的语义。该标准的作者允许编译器作者根据其对于编译器预期目的是否必要而支持这种语义;不幸的是,目前尚没有任何标准方法可以将适合于此类用途的编译器与不适合此类用途的编译器区分开。