我非常有信心在程序启动时分配(并初始化,如果适用)全局声明的变量.
int globalgarbage; unsigned int anumber = 42;
但是在函数中定义的静态的呢?
void doSomething() { static bool globalish = true; // ... }
globalish
分配的空间是什么时候?我猜测程序什么时候开始.但是它也被初始化了吗?或者它doSomething()
是在第一次调用时初始化的?
我很好奇,所以我编写了以下测试程序并用g ++ 4.1.2版编译.
include#include 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
C++标准中的一些相关措辞:
3.6.2非本地对象的初始化[basic.start.init]
1
具有静态存储持续时间(basic.stc.static)的对象的存储应在任何其他初始化发生之前进行零初始化(dcl.init).具有使用常量表达式(expr.const)初始化的静态存储持续时间的POD类型(basic.types)的对象应在任何动态初始化发生之前初始化.具有在同一翻译单元中定义并动态初始化的静态存储持续时间的命名空间作用域的对象应按其定义出现在翻译单元中的顺序进行初始化.[注意: dcl.init.aggr 描述了聚合成员初始化的顺序.stmt.dcl中描述了本地静态对象的初始化.]
[下面的更多文本为编译器编写者添加更多自由]
6.7声明声明[stmt.dcl]
...
4
零初始化(dcl.init具有静态存储时间(所有本地对象)basic.stc.static任何其他初始化发生之前执行).具有使用常量表达式初始化的静态存储持续时间的POD类型(basic.types)的本地对象在其首次输入块之前初始化.允许实现在静态存储持续时间内执行其他本地对象的早期初始化,条件是允许实现静态初始化具有命名空间范围内的静态存储持续时间的对象(basic.start.init)).否则,在第一次控制通过其声明时初始化这样的对象; 这样的对象在初始化完成时被认为是初始化的.如果通过抛出异常退出初始化,则初始化未完成,因此下次控制进入声明时将再次尝试初始化.如果控件在初始化对象时重新输入声明(递归),则行为未定义.[ 例如:
int foo(int i) { static int s = foo(2*i); // recursive call - undefined return i+1; }- 结束例子 ]
五
当且仅当构造变量时,将执行具有静态存储持续时间的本地对象的析构函数.[注意: basic.start.term 描述了破坏具有静态存储持续时间的本地对象的顺序.]
所有静态变量的内存在程序加载时分配.但是本地静态变量在第一次使用时创建并初始化,而不是在程序启动时初始化.还有关于一些良好的阅读,和静在一般情况下,在这里.总的来说,我认为其中一些问题取决于实现,特别是如果你想知道这些东西的位置在哪里.
编译器将foo
在程序加载时分配函数中定义的静态变量,但是编译器还会向函数添加一些附加指令(机器代码),foo
以便在第一次调用它时,这个附加代码将初始化静态变量(例如,如果适用,调用构造函数).
@Adam:编译器在幕后注入代码是你看到的结果的原因.
我尝试再次测试来自Adam Pierce的代码并添加了两个案例:类中的静态变量和POD类型.我的编译器是g ++ 4.8.1,在Windows操作系统(MinGW-32)中.结果是类中的静态变量与全局变量一样.在进入main函数之前将调用它的构造函数.
结论(对于g ++,Windows环境):
类中的全局变量和静态成员:在进入main函数(1)之前调用构造函数.
局部静态变量:构造函数仅在第一次执行到达其声明时被调用.
如果Local静态变量是POD类型,则在进入main函数(1)之前也会初始化它.POD类型示例:static int number = 10;
(1):正确的状态应该是:"在调用来自同一翻译单元的任何函数之前".但是,为简单起见,如下例所示,那么它就是主要功能.
包括
#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; static test t; // static member }; test test::t("static in class"); test t("global variable"); void f() { static test t("static variable"); static int num = 10 ; // POD type, init before enter main function 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; }
结果:
static in class created 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 static in class destroyed
有人在Linux环境下测试过?