14

如果我有一个名为 Test ::

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

staticVector什么时候被构造,什么时候被破坏?

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

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

请注意,当静态修饰符出现在 C++、Java 和 C# 中的类定义中的变量声明中时,它与变量的生命周期无关。在这种情况下,这意味着变量是类变量,而不是实例变量。保留字的多次使用可能会使学习该语言的人感到困惑。

你明白了吗?:(

4

5 回答 5

17

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


首先是可能性列表。

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

命名空间静态

  • 有两种初始化方法。静态(打算在编译时发生)和动态(打算在运行时发生)初始化。
  • 静态初始化发生在任何动态初始化之前,不考虑翻译单元关系。
  • 动态初始化在翻译单元中是有序的,而静态初始化没有特定的顺序。同一翻译单元的命名空间范围的对象按照其定义出现的顺序动态初始化。
  • 使用常量表达式初始化的 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 之前发生。但是,初始化必须在第一次使用其翻译单元的对象或函数之前发生。这对于动态可加载库很重要。

类静态

  • 表现得像命名空间静态。
  • 有一个关于编译器是否允许在第一次使用其翻译单元的函数或对象时初始化类静态的错误报告(在 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);  
}

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

还要注意,销毁的顺序是对象构建完成的确切顺序。这是一种常见的情况,在 C++ 中的各种情况下都会发生,包括破坏临时对象。

于 2009-07-03T17:15:59.987 回答
15

与常规静态(全局)变量完全一样。

于 2009-07-03T14:33:44.330 回答
5

它是在全局变量与全局变量一起构造和销毁的同时构造的。

于 2009-07-03T14:34:46.217 回答
3

简单来说:
在构造全局变量的时候,就构造了一个静态成员变量。全局变量的构造顺序没有定义,但是在进入主函数之前发生。

当全局变量被销毁时,就会发生销毁。

全局变量按照它们被构造的相反顺序被销毁;退出主功能后。

问候,
欧文斯

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

PPS:您的代码仅声明了一个静态成员变量,但并未对其进行初始化。要初始化它,您必须在其中一个编译单元中编写:

std::vector 测试::staticVector;

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

于 2009-07-03T15:07:52.860 回答
1

一些特定的 VC++ 信息,以防您正在使用:

  1. 静态类变量的构造与其他静态/全局变量同时发生。
  2. 在 windows 中,CRT 启动函数负责这个构造。这是您编译的大多数程序的实际入口点(它是调用您的 Main/Winmain 函数的函数)。此外,它还负责初始化整个 C 运行时支持(例如您需要它来使用 malloc)。
  3. 构造顺序是未定义的,但是当使用 microsoft VC 编译器时,基本类型的构造顺序是可以的,例如它是合法且安全的编写

statics.h: ... MyClass 声明 ... static const int a; 静态int b;静态 int ar[]; 静态.cpp:

const int MyClass::a = 2;
int MyClass::b = a+3;
int MyClass::ar[a] = {1,2}
于 2009-07-03T15:17:15.833 回答