函数级静态变量何时分配/初始化?
我非常有信心在程序启动时分配(并初始化,如果适用)全局声明的变量。
int globalgarbage; unsigned int anumber = 42;
但是在函数中定义的静态变量呢?
void doSomething() { static bool globalish = true; // ... }
什么时候分配" globalish"的空间?我猜该程序何时启动。但是它也被初始化了吗?还是在首次调用doSomething()时初始化?
解决方案
回答
静态变量分配在代码段内-它们是可执行映像的一部分,因此被映射到已初始化的映像中。
函数范围内的静态变量被视为相同,作用域纯粹是语言级别的构造。
因此,可以确保将静态变量初始化为0(除非我们指定其他内容),而不是将其初始化为未定义的值。
我们可以利用初始化的其他一些方面-例如共享段允许一次运行的可执行文件的不同实例访问相同的静态变量。
在C ++(全局范围内)中,静态对象在C运行时库的控制下将其构造函数作为程序启动的一部分进行调用。在Visual C ++中,至少可以通过init_seg编译指示来控制对象的初始化顺序。
回答
我对此感到很好奇,因此我编写了以下测试程序,并使用g ++ 4.1.2版对其进行了编译。
include <iostream> #include <string> using namespace std; class test { public: test(const char *name) : _name(name) { cout << _name << " created" << endl; } ~test() { cout << _name << " destroyed" << endl; } string _name; }; test t("global variable"); void f() { static test t("static variable"); test t2("Local variable"); cout << "Function executed" << endl; } int main() { test t("local to main"); cout << "Program start" << endl; f(); cout << "Program end" << endl; return 0; }
结果不是我预期的。直到第一次调用该函数时,才调用静态对象的构造函数。这是输出:
global variable created local to main created Program start static variable created Local variable created Function executed Local variable destroyed Program end local to main destroyed static variable destroyed global variable destroyed
回答
所有静态变量的内存在程序加载时分配。但是局部静态变量是在首次使用它们时创建的,而不是在程序启动时进行初始化。关于这一点,这里有一些不错的读物,以及一般的静态知识。总的来说,我认为其中一些问题取决于实现方式,特别是如果我们想知道这些东西在内存中的位置。
回答
编译器将在程序加载时分配在函数foo中定义的静态变量,但是编译器还将在函数foo中添加一些添加指令(机器代码),以便首次调用此添加代码将初始化静态变量(例如,调用构造函数,如果适用)。
@Adam:这是编译器在后台注入代码的原因,是我们看到结果的原因。
回答
Or is it initialized when doSomething() is first called?
是的。除此之外,它还使我们可以在合适的时候初始化全局访问的数据结构,例如在try / catch块内部。例如。代替
int foo = init(); // bad if init() throws something int main() { try { ... } catch(...){ ... } }
你可以写
int& foo() { static int myfoo = init(); return myfoo; }
并在try / catch块中使用它。在第一次调用时,变量将被初始化。然后,在第一个和下一个调用中,将返回其值(通过引用)。
回答
C ++标准的一些相关词汇:
3.6.2 Initialization of non-local objects [basic.start.init] 1 The storage for objects with static storage duration (basic.stc.static) shall be zero-initialized (dcl.init) before any other initialization takes place. Objects of POD types (basic.types) with static storage duration initialized with constant expressions (expr.const) shall be initialized before any dynamic initialization takes place. Objects of namespace scope with static storage duration defined in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit. [Note: dcl.init.aggr describes the order in which aggregate members are initialized. The initialization of local static objects is described in stmt.dcl. ] [more text below adding more liberties for compiler writers] 6.7 Declaration statement [stmt.dcl] ... 4 The zero-initialization (dcl.init) of all local objects with static storage duration (basic.stc.static) is performed before any other initialization takes place. A local object of POD type (basic.types) with static storage duration initialized with constant-expressions is initialized before its block is first entered. An implementation is permitted to perform early initialization of other local objects with static storage duration under the same conditions that an implementation is permitted to statically initialize an object with static storage duration in namespace scope (basic.start.init). Otherwise such an object is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control re-enters the declaration (recursively) while the object is being initialized, the behavior is undefined. [Example: int foo(int i) { static int s = foo(2*i); // recursive call - undefined return i+1; } --end example] 5 The destructor for a local object with static storage duration will be executed if and only if the variable was constructed. [Note: basic.start.term describes the order in which local objects with static storage duration are destroyed. ]