在C++中,用自身初始化全局变量是否具有未定义的行为


int i = i;
int main() { 
int a = a;
return 0;
} 

int a = a肯定有未定义的行为(UB),有关它的更多详细信息请参阅读取未初始化的值总是一种未定义的行为吗?还是有例外

但是int i = i呢?在C++中,我们可以将非恒定值分配给全局变量。i在遇到声明之前被声明并初始化为零(因为它具有文件作用域)。在这种情况下,我们将在稍后的定义中将0分配给它。可以肯定地说,这没有UB吗?

令人惊讶的是,这不是未定义的行为。

静态初始化〔basic.start.Static〕

如果变量或临时对象具有静态或线程存储的持续时间是恒定初始化的如果未执行常量初始化,带有static的变量存储持续时间或线程存储持续时间初始化为零。零初始化和常量初始化统称为静态初始化;所有其他初始化都是动态的初始化所有静态初始化都强烈发生在动态初始化

重要部件采用粗体"静态初始化";包括全局变量初始化;静态存储持续时间";包括全局变量,上述条款适用于此处:

int i = i;

这不是恒定的初始化。因此,零初始化是根据上面的子句完成的(对于基本整数类型,零初始化意味着它被设置为0,这不足为奇)。上面的子句还指定在动态初始化之前必须进行零初始化。

那么,这里发生了什么:

  1. i被初始化为0
  2. i随后从其自身进行动态初始化,因此它仍然保持为0

i的行为可能未定义,因为根据您阅读标准的方式,您可能会在i的生命周期开始之前阅读它。

[basic.life]/1.2

T型物体的寿命开始于:

--其初始化(如果有的话)已完成。。。

如另一个答案中所述,i被初始化两次:首先是静态初始化为零,然后用i动态初始化。

哪个初始化开始了生存期?第一个还是最后一个?

该标准含糊不清,其中有相互矛盾的注释(尽管所有注释都是非规范性的)。首先,[basic.life]/6中有一个脚注(感谢@eerorika)明确表示动态初始化开始了生命周期:

[basic.life]/6

在一个对象的寿命开始之前,但在该对象将占用的存储器被分配26之后

26)例如,在具有静态存储持续时间的对象的动态初始化之前。。。

这种解释对我来说最有意义,因为否则在类实例进行动态访问之前访问它们是合法的初始化,然后才能建立不变量(包括标准定义的标准库类)。

[basic.start.static]/3中也有一个相互矛盾的注释,但这个注释比我上面提到的那个要老。

在我看来,int i = i;有未定义的行为,不是由不确定的值引起的。术语不确定值是为具有自动或动态存储持续时间的对象设计的。

[basic.indet#1]

当获得自动或动态存储持续时间的对象的存储时,该对象具有不确定值,如果未对该对象执行初始化,则该对象将保留不确定值,直到该值被替换([expr.ass])。

[basic.indet#2]

如果评估产生了不确定的值,则行为是未定义的,以下情况除外。。。

在您的示例中,名为i的对象具有静态存储持续时间,因此它不在谈论不确定值的范围内。而且,这样一个对象在任何动态初始化之前都有一个零初始化,根据〔basic.start.static#2〕

零初始化和常量初始化统称为静态初始化;所有其他初始化都是动态初始化。所有静态初始化都强烈地发生在([intro.races])任何动态初始化之前。

因此,其初始值为零。当CCD_ 17被用作初始化器来初始化自身时。这是一个动态初始化,它遵循[dcl.init].

否则,正在初始化的对象的初始值是初始值设定项表达式的值(可能已转换)。

它违反了〔basic.lifetime〕中的规则

程序有未定义的行为,如果:

  • glvalue用于访问对象,或者
[/div>

最新更新