2009-09-14 56 views
53

似乎没有简单的答案,但是有什么假设可以安全地做出什么时候可以访问静态类字段?何时初始化静态C++类成员?

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

+2

让我很高兴我现在在做.net开发,答案是“就在你使用它之前”。 – Massif 2009-09-14 14:09:13

+0

我同意你在编辑中的结论。与静态初始化并行的唯一处理是其他静态初始化。 (当然,这可以与实现所执行的其他内容同时进行,但不是您编写的任何内容。) – 2009-09-14 14:10:10

+5

如果您想在C++中播放该卡,除非我们只在需要时付费。 :P – GManNickG 2009-09-14 14:10:39

回答

47

该标准保证了两件事 - 即在同一翻译单元中定义的对象(通常意思是。CPP文件)在其定义的顺序初始化(不声明):

3.6.2

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

其他保证的是从翻译单元静态对象的初始化使用从该转换单元中的任何对象或函数之前会做:

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

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

编辑 正如Suma的评论所指出的那样,它也保证它们在输入main之前被初始化。

+8

我认为还有一件事情可以保证,“它们在程序启动之前(即在输入main之前)被初始化” - 这应该包含在我认为的答案中。 – Suma 2010-12-29 18:51:11

+0

如果我有一个具有“main()”函数的二进制文件,并且静态是与二进制文件动态链接的库的一部分,该怎么办?静态在调用main之前初始化? – Dilawar 2015-04-04 13:27:09

+2

由于EDIT的原因,现在上面的答案有矛盾。第二个黄色框(引用标准)说:“如果初始化是在main()...”的第一个语句之后的某个时间点推迟的,并且您添加了“保证在main()之前发生”,与之相矛盾,并且不引用标准。 – 2015-05-06 11:45:15

1

我相信它可以在执行过程中随时访问。未定义的是静态变量的初始化顺序。

0

这个问题并没有一个完全微不足道的答案,但基本上它们是在控制传递到程序的入口点(main)之前初始化的。 (就我所知),它们被初始化的顺序是未定义的,并且可能是编译器特定的。

编辑:澄清,你添加的假设是正确的。只要你只是在主入口后访问它,你并不需要担心它初始化的时间/方式。它将在那个时候初始化。

1

它们可以在实现文件(.c/cpp/cc)文件中初始化。不要在.h中初始化它们,因为编译器会抱怨多个定义。

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

17

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

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

当多个CPP文件中存在两个或多个(静态数据的)定义时,处理CPP文件的顺序是未定义的/实现特定的。如果全局变量(在程序启动之前调用)的构造函数引用在另一个CPP文件中定义的另一个全局变量(可能尚未构建),则会出现此问题。然而,迈尔斯C++有效(这是名为确保他们使用之前全局对象初始化)的项目47并描述了一个变通......

  • 定义一个静态变量中头文件(它是静态的,所以你可以有多个实例没有连接器抱怨)

  • 让变量的构造函数调用你需要的任何东西(特别是构造在头文件中声明的全局单例)

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

+2

在Effective C++ 3rd版本中它是项目4:确保对象在使用之前被初始化。 (并在那里讨论非局部静态变量,例如静态类成员) – 2015-10-05 13:39:46

+1

并不是所有的静态对象都保证在'main'输入前被初始化。请参阅Tadeusz Kopec对引用标准的这个问题的回答: “它是实现定义的,是否命名空间对象的动态初始化(dcl.init,class.static,class.ctor,class.expl.init)范围是在主要的第一个陈述之前完成的。“ – 2017-10-05 13:52:37

-1

我认为下面的一个进程的主线程将执行,以便

  1. CRT库

  2. 静态初始化

  3. 执行的主要的初始化()函数以下五个步骤

  4. static unitialization

    CRT库

你想从其它静态初始化代码引用静态

  • unitialization? 也许以下代码工作:

    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; 
        } 
    } 
    
  • 3

    您在编辑中的最终结论是正确的。但问题在于类本身是静态的。更容易的说,我的代码将有类静态成员不引用其他全局数据/类静态成员,但一旦你采取这种方式,事情很快就会出错。我发现在实践中有一种方法没有类静态数据成员,而是类静态包装器方法。这些方法可以将静态对象保存在其自身内部。对于例如

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

    注:较早的回答说:

    其他保证的是从翻译单元静态对象 的初始化使用任何物体或从该转换单元中 功能之前,将完成

    这不完全正确,标准在这里被错误地推断出来。如果在输入main之前调用翻译单元的功能,则这可能不成立。