静态 C + + 类成员何时初始化?

这个问题似乎没有简单的答案,但是有没有可以安全地假设什么时候可以访问静态类字段?

编辑: 唯一安全的假设似乎是所有静态在程序开始之前被初始化(调用 main)。那么,只要我不从其他静态初始化代码中引用静态,我就没什么可担心的了?

40615 次浏览

我相信在行刑过程中可以随时进入。尚未定义的是静态变量的初始化顺序。

这个问题没有一个完全无关紧要的答案,但基本上它们是在控制权传递到程序的入口点(main)之前被初始化的。初始化它们的顺序(据我所知)是未定义的,可能是特定于编译器的。

编辑: 澄清一下,你补充的假设是正确的。只要你只是在主入口之后访问它,你就不必担心什么时候或怎样初始化它。到那时它将被初始化。

它们可以在实现文件(。C/cpp/cc)文件。不要初始化它们。H as 编译器会抱怨多个定义。

它们通常在 main 之前初始化,但是顺序是未知的,因此要避免依赖性。它们当然可以在成员函数中访问。请记住,静态成员的初始化顺序是未知的。我建议将静态成员封装到静态函数中,以检查该成员是否已初始化。

它们在程序启动之前(即在输入 main之前)被初始化。

当一个 CPP 文件中有两个或两个以上的定义(静态数据)时,它们将按照在文件中定义的顺序进行初始化(在文件中更早/更高定义的定义将在下一个定义之前进行初始化)。

当在多个 CPP 文件中有两个或多个定义(静态数据)时,处理 CPP 文件的顺序是未定义的/特定于实现的。如果全局变量的构造函数(在程序启动之前调用)引用另一个在不同的 CPP 文件中定义的全局变量,而这个 CPP 文件可能还没有构造,那么就会出现这个问题。然而,梅耶斯的 有效的 C + + (标题为 确保在使用全局对象之前已初始化它们)的第47项确实描述了一种变通方法..。

  • 在头文件中定义一个静态变量(它是静态的,因此您可以拥有它的多个实例,而不用担心链接器)

  • 让该变量的构造函数调用您需要的任何内容(特别是构造在头中声明的全局单例)

... 它说这是一种技术,可用于一些系统头文件,例如,以确保 cin全局变量初始化之前,甚至您的静态变量的构造函数使用它。

该标准保证了两件事情——在同一个翻译单元中定义的对象(通常意味着。Cpp 文件)按照它们的定义(而不是声明)进行初始化:

3.6.2

对于具有静态存储持续时间的对象(basic.stc.static) ,在进行任何其他初始化之前,存储应为零初始化(dcl.init)。零初始化和使用常量表达式的初始化统称为静态初始化; 所有其他初始化都是动态初始化。使用常量表达式(expr.const)初始化具有静态存储时间的 POD 类型(basic.type)的对象应该在进行任何动态初始化之前进行初始化。在同一翻译单元的命名空间范围内定义了静态存储持续时间并动态初始化的对象应该按照它们的定义在翻译单元中出现的顺序进行初始化。

另一个保证是,在使用翻译单元中的任何对象或函数之前,将先从翻译单元初始化静态对象:

命名空间范围对象的动态初始化(dcl.init、 class.static、 class.ctor、 class.exp.init)是否在 main 的第一个语句之前完成,这是实现定义的。如果初始化被推迟到 main 的第一个语句之后的某个时间点,那么它应该发生在第一次使用与要初始化的对象在同一个转换单元中定义的任何函数或对象之前。

没有其他的保证(特别是定义在不同翻译单元中的对象的初始化顺序是实现定义的)。

剪辑 正如苏马河的评论所指出的,它还保证在输入 main之前对它们进行初始化

我认为进程的主线程将按顺序执行以下五个步骤

  1. CRT 库的初始化

  2. 静态初始化

  3. Main ()函数的执行

  4. 静态统一化静态统一化

  5. 阴极射线管库的一体化

你想从其他静态初始化代码的参考静态? 也许下面的密码有用:

class A;
static auto_ptr<A> a(auto_ptr<A>(&GetStaticA()));
A &GetStaticA(void)
{
static A *a = NULL; //the static basic type variables initialized with constant experession will be initialized earlier than the other static ones
if (a == NULL)
{
a = new A();
return *a;
}
}

您在编辑中的最终结论是正确的。但问题是类本身是静态的。我的代码中的类静态成员不会引用其他全局数据/类静态成员,但是一旦采用这种方法,很快就会出问题。有一种方法在实践中非常有用,即不使用类静态数据成员,而使用类静态包装器方法。然后,这些方法可以将静态对象保存在其内部。举例来说。

TypeX* Class2::getClass1Instance()
{
static TypeX obj1;
return &obj1;
}

注意: 之前的答案是:

另一个保证是静态对象的初始化 从一个翻译单位将完成之前,使用任何对象或 这个翻译单元的功能

这并不完全正确,这里推断的标准也不正确。如果在输入 main 之前调用来自翻译单元的函数,则这种情况可能不成立。