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

Ara*_*raK 11 c++ static-members lifetime

如果我有一个名为Test ::

class Test
{
    static std::vector<int> staticVector;
};
Run Code Online (Sandbox Code Playgroud)

什么时候构造staticVector以及什么时候它被破坏?

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

只是为了澄清,在阅读编程语言概念(Sebesta Ch-5.4.3.1)后,我想到了这个问题,它说::

请注意,当静态修饰符出现在C++,Java和C#中的类定义中的变量声明中时,它与变量的生命周期无关.在该上下文中,它表示变量是类变量,而不是实例变量.保留字的多次使用可能使学习语言的人特别困惑.

你明白了吗?:(

Joh*_*itb 17

我想写一些关于initializaton的文本,我可以稍后链接到.


首先是可能性列表.

  • 命名空间静态
  • 静态
  • 局部静态

命名空间静态

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

例子:

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

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

A a(1);
A b(2);
Run Code Online (Sandbox Code Playgroud)

以下是基于同一类的打印 A(2) A(1)

extern A a;
A b(2);
A a(1);
Run Code Online (Sandbox Code Playgroud)

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

char const *msg = "abc";
Run Code Online (Sandbox Code Playgroud)

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

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

类静态

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

局部静态

  • 对于当地静力学,会发生特殊规则.
  • 使用常量表达式初始化的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);  
}
Run Code Online (Sandbox Code Playgroud)

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

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


Mag*_*off 13

完全像常规静态(全局)变量.

  • 一些挑剔,但重要的挑选:顺序取决于它们的定义顺序,而不是它们的声明顺序:在下面的代码中,a在b之后创建,即使a在b之前声明:**`extern A a ; B b(a); A;`** - 此代码可能会产生令人惊讶的结果. (6认同)
  • 破坏静态/全局变量的顺序与创建的顺序相反. (4认同)
  • @skizz:在特定的编译单元中,订单被明确定义为声明的顺序.在多个编译单元中,它是未定义的(或未指定的).但问题是关于破坏. (3认同)
  • 除此之外,唯一要做的是静态/全局变量构造的顺序是未定义的. (2认同)

Goz*_*Goz 5

它在构造全局变量的同时被构造和销毁。