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

发布于 2024-07-26 06:15:25 字数 563 浏览 6 评论 0原文

如果我有一个名为 Test :: 的类,

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

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

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

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

请注意,当 static 修饰符 出现在声明中 C++ 中类定义中的变量, Java和C#,没有关系 变量的生命周期。 在那里面 上下文,这意味着变量是 类变量,而不是 实例变量。 多重用途 保留字的定义可能会令人困惑 特别是对于那些学习 语言。

你明白了吗? :(

If I have a class called Test ::

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

when does staticVector get constructed and when does it get destructed ?

Is it with the instantiation of the first object of Test class, or just like regular static variables ?

Just to clarify, this question came to my mind after reading Concepts of Programming Languages (Sebesta Ch-5.4.3.1) and it says ::

Note that when the static modifier
appears in the declaration of a
variable in a class definition in C++,
Java and C#, it has nothing to do with
the lifetime of the variable. In that
context, it means the variable is a
class variable, rather than an
instance variable. The multiple use
of a reserved word can be confusing
particularly to those learning the
language.

did you understand? :(

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

北音执念 2024-08-02 06:15:25

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


首先列出可能性。

  • Namespace Static
  • Class Static
  • Local Static

Namespace Static

  • 有两种初始化方法。 静态(旨在在编译时发生)和动态(旨在在运行时发生)初始化。
  • 静态初始化发生在任何动态初始化之前,不考虑翻译单元关系。
  • 动态初始化在翻译单元中是有顺序的,而静态初始化没有特定的顺序。 同一翻译单元的名称空间范围的对象按照其定义出现的顺序动态初始化。
  • 使用常量表达式初始化的 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 接收动态初始化。 但因为 msg 的静态初始化(char const* 是 POD 类型,"abc" 是地址常量表达式)发生在这之前,这很好,并且 msg 保证被正确初始化。

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

Class Static

- Behave like namespace statics.
- There is a bug-report on whether the compiler is allowed to initialize class statics on the first use of a function or object of its translation unit too (after main). The wording in the Standard currently only allows this for namespace scope objects - but it seems it intends to allow this for class scope objects too. Read [Objects of Namespace Scope](http://groups.google.com/group/comp.std.c++/browse_thread/thread/28cfef85456512c8).
- For class statics that are member of templates the rule is that they are only initialized if they are ever used. Not using them will not yield to an initialization. Note that in any case, initialization will happen like explained above. Initialization will not be delayed because it's a member of a template.

Local Static

- For local statics, special rules happen.
- POD type objects initialized with constant expression are initialized before their block in which they are defined is entered.
- Other local static objects are initialized at the first time control passes through their definition. Initialization is not considered to be complete when an exception is thrown. The initialization will be tried again the next time.

示例:下面的程序打印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++ 中的各种情况下都会发生,包括破坏临时对象。

I want to write some text about initializaton too, which i can later link to.


First the list of possibilities.

  • Namespace Static
  • Class Static
  • Local Static

Namespace Static

  • There are two initialization methods. static (intended to happen at compile time) and dynamic (intended to happen at runtime) initialization.
  • Static Initialization happens before any dynamic initialization, disregarding of translation unit relations.
  • Dynamic Initiaization is ordered in a translation unit, while there is no particular order in static initialization. Objects of namespace scope of the same translation unit are dynamically initialized in the order in which their definition appears.
  • POD type objects that are initialized with constant expressions are statically initialized. Their value can be relied on by any object's dynamic initialization, disregarding of translation unit relations.
  • If the initialization throws an exception, std::terminate is called.

Examples:

The following program prints A(1) A(2)

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

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

And the following, based on the same class, prints A(2) A(1)

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

Let's pretend there is a translation unit where msg is defined as the following

char const *msg = "abc";

Then the following prints abc. Note that p receives dynamic initialization. But because the static initialization (char const* is a POD type, and "abc" is an address constant expression) of msg happens before that, this is fine, and msg is guaranteed to be correctly initialized.

extern const char *msg;
struct P { P() { std::printf("%s", msg); } };
P p;
  • Dynamic initialization of an object is not required to happen before main at all costs. The initialization must happen before the first use of an object or function of its translation unit, though. This is important for dynamic loadable libraries.

Class Static

- Behave like namespace statics.
- There is a bug-report on whether the compiler is allowed to initialize class statics on the first use of a function or object of its translation unit too (after main). The wording in the Standard currently only allows this for namespace scope objects - but it seems it intends to allow this for class scope objects too. Read [Objects of Namespace Scope](http://groups.google.com/group/comp.std.c++/browse_thread/thread/28cfef85456512c8).
- For class statics that are member of templates the rule is that they are only initialized if they are ever used. Not using them will not yield to an initialization. Note that in any case, initialization will happen like explained above. Initialization will not be delayed because it's a member of a template.

Local Static

- For local statics, special rules happen.
- POD type objects initialized with constant expression are initialized before their block in which they are defined is entered.
- Other local static objects are initialized at the first time control passes through their definition. Initialization is not considered to be complete when an exception is thrown. The initialization will be tried again the next time.

Example: The following program prints 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);  
}

In all the above cases, in certain limited cases, for some objects that are not required to be initialized statically, the compiler can statically initialize it, instead of dynamically initializing it. This is a tricky issue, see this answer for a more detailed example.

Also note that the order of destruction is the exact order of the completion of construction of the objects. This is a common and happens in all sort of situations in C++, including in destructing temporaries.

一抹苦笑 2024-08-02 06:15:25

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

Exactly like regular static (global) variables.

美煞众生 2024-08-02 06:15:25

它是在全局变量被构造的同时被构造的,并且也与全局变量一起被破坏。

It gets constructed at the same time the global variables get constructed and destructed along with the globals as well.

陈甜 2024-08-02 06:15:25

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

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

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

问候,
Ovanes

P.S.:我建议看一下 C++ 标准,它解释(定义)了如何以及何时构造或析构全局或静态成员变量。

PPS:您的代码只声明了一个静态成员变量,但没有初始化它。 要初始化它,您必须在编译单元之一中编写:

std::vector Test::staticVector;

std::vector Test::staticVector=std::vector(/* 这里是 ctor 参数 */);

Simply speaking:
A static member variable is constructed when the global variables are constructed. The construction order of global variables is not defined, but it happens before the main-function is entered.

Destruction happens when global variables are destroyed.

Global variables are destroyed in the reversed order they were constructed; after exiting the main-function.

Regards,
Ovanes

P.S.: I suggest to take a look at C++-Standard, which explains (defines) how and when global or static member variables are constructed or destructed.

P.P.S.: Your code only declares a static member variable, but does not initialize it. To initialize it you must write in one of the compilation units:

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

℉絮湮 2024-08-02 06:15:25

一些特定的 VC++ 信息(如果您正在使用这些信息):

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

statics.h是合法且安全的:
... MyClass 声明 ...
静态常量 int a;
静态 int b;
静态 int ar[];
}
静态.cpp:

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

Some specific VC++ information in case that's what you're using:

  1. Static class variables construction occurs at same time as other static/global variables.
  2. In windows, the CRT startup function is responsible for this construction.
    This is the actual entry point of most programs you compile (it is the function which calls your Main/Winmain function).
    In addition, it is responsible for initializing the entire C runtime support (for example you need it to use malloc).
  3. The order of construction is undefined, however when using the microsoft VC compiler the order of construction for basic types will be OK, for example it is legal and safe to write

statics.h:
... MyClass declaration ...
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}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文