C ++中类静态变量的生命周期是多少?

时间:2009-07-03 14:31:49

标签: c++ static-members lifetime

如果我有一个名为Test ::

的类
class Test
{
    static std::vector<int> staticVector;
};

何时构建 staticVector 以及何时被破坏?

是实例化Test类的第一个对象,还是像常规静态变量一样?

只是为了澄清,在阅读编程语言概念(Sebesta Ch-5.4.3.1)并且它说::

后,我想到了这个问题。
  

请注意,当静态修饰符时   出现在a的声明中   C ++中类定义中的变量,   Java和C#,它与它无关   变量的生命周期。在那里面   上下文,它意味着变量是一个   类变量,而不是一个   实例变量。多次使用   保留字的含义可能令人困惑   特别是那些学习的人   语言。

你明白了吗? :(

6 个答案:

答案 0 :(得分:16)

我想写一些关于初始化的文本,我可以稍后链接到。


首先列出可能性。

  • 命名空间静态
  • Class Static
  • 本地静态

名称空间静态

  • 有两种初始化方法。 static (打算在编译时发生)和 dynamic (打算在运行时发生)初始化。
  • 静态初始化任何动态初始化之前发生,忽略翻译单元关系。
  • 动态初始化在翻译单元中排序,而静态初始化中没有特定顺序。同一翻译单元的命名空间范围的对象按其定义出现的顺序动态初始化。
  • 使用常量表达式初始化的POD类型对象是静态初始化的。任何对象的动态初始化都可以依赖它们的值,而忽略翻译单元关系。
  • 如果初始化引发异常,则调用std::terminate

示例:

以下程序打印 A(1) A(2)

struct A { 
  A(int n) { std::printf(" A(%d) ", n); } 
};

A a(1);
A b(2);

以下内容基于同一类打印 A(2) A(1)

extern A a;
A b(2);
A a(1);

让我们假装有一个翻译单元,其中msg被定义为以下

char const *msg = "abc";

然后以下打印 abc 。请注意p接收动态初始化。但是因为静态初始化(char const*是POD类型,并且"abc"是地址常量表达式)msg之前发生,所以这很好,并且msg得到保证要正确初始化。

extern const char *msg;
struct P { P() { std::printf("%s", msg); } };
P p;
  • 对象的动态初始化不需要在main之前不惜一切代价发生。但是,初始化必须在首次使用其翻译单元的对象或功能之前进行。这对于动态可加载库非常重要。

Class Static

  • 表现得像命名空间静态。
  • 有一个错误报告,关于是否允许编译器在首次使用其翻译单元的函数或对象时(在main之后)初始化类静态。标准中的措辞目前仅允许这用于命名空间范围对象 - 但似乎它也打算允许这对于类范围对象。阅读Objects of Namespace Scope
  • 对于作为模板成员的类静态,规则是只有在使用它们时才初始化它们。不使用它们不会产生初始化。请注意,在任何情况下,初始化都会发生,如上所述。初始化不会延迟,因为它是模板的成员。

本地静态

  • 对于当地静力学,会发生特殊规则。
  • 使用常量表达式初始化的POD类型对象在输入定义它们的块之前进行初始化。
  • 其他本地静态对象在控件第一次通过其定义时初始化。抛出异常时,初始化不被认为是完整的。下次将再次尝试初始化。

示例:以下程序打印 0 1

struct C { 
  C(int n) { 
    if(n == 0)
      throw n;
    this->n = n;
  }
  int n;
};

int f(int n) {
  static C c(n);
  return c.n;
}

int main() {
  try { 
    f(0); 
  } catch(int n) { 
    std::cout << n << " "; 
  }
  f(1); // initializes successfully
  std::cout << f(2);  
}

在上述所有情况下,在某些有限的情况下,对于某些不需要静态初始化的对象,编译器可以静态初始化它,而不是动态初始化它。这是一个棘手的问题,请参阅this answer以获取更详细的示例。

另请注意,破坏的顺序是完成对象构造的确切顺序。这在C ++中的各种情况下都很常见,包括破坏临时性。

答案 1 :(得分:12)

与常规静态(全局)变量完全相同。

答案 2 :(得分:4)

它是在构造和破坏全局变量的同时构造的。

答案 3 :(得分:2)

简单地说:
构造全局变量时构造静态成员变量。未定义全局变量的构造顺序,但它在输入main函数之前发生。

当全局变量被破坏时发生破坏。

全局变量按其构建的相反顺序销毁;退出主功能后。

的问候,
Ovanes

P.S。:我建议看看C ++ - Standard,它解释(定义)如何以及何时构造或破坏全局或静态成员变量。

P.P.S。:您的代码只声明一个静态成员变量,但不会初始化它。要初始化它,您必须在其中一个编译单元中写入:

std :: vector Test :: staticVector;

std :: vector Test :: staticVector = std :: vector(/ * ctor params here * /);

答案 4 :(得分:1)

如果您使用的是某些特定的VC ++信息:

  1. 静态类变量构造与其他静态/全局变量同时发生。
  2. 在Windows中,CRT启动功能负责此构造。 这是您编译的大多数程序的实际入口点(它是调用Main / Winmain函数的函数)。 此外,它还负责初始化整个C运行时支持(例如,您需要使用malloc)。
  3. 构造的顺序是未定义的,但是当使用microsoft VC编译器时,基本类型的构造顺序是可以的,例如它是合法且安全的。
  4. statics.h: ... MyClass声明......     static const int a;     static int b;     static int ar []; } statics.cpp:

    const int MyClass::a = 2;
    int MyClass::b = a+3;
    int MyClass::ar[a] = {1,2}
    

答案 5 :(得分:-1)

静态类成员变量意味着即使同一个类中有多个对象,该变量对于该类的所有对象也是相同的。

所以,我想说,它是在第一个对象被实例化时被构造的,并且在最后一个对象被解构时被破坏。