关于全局、static对象/变量的初始化问题
1. 全局变量、static变量的初始化时机:main()函数执行之前(或者说main中第一个用户语句执行之前)。
2. 初始化顺序。
1)全局对象、外部static对象
a)同一编译单元(同一源文件)中,按照对象/变量的定义顺序初始化。
b)不同编译单元,C++标准未保证初始化先后顺序,只保证都在main()之前初始化完成。
2)函数内部local static变量,在该函数调用过程中第一次遇到该static变量时初始化。
基于以上观点,大师们建议少用全局变量,全局变量之间要消除依赖关系——特别是初始化依赖关系!
写个示例程序验证下这些变量的初始化,中间的注释部分就作为上面结论的一些补充吧。
class CA
{
public:
class CInner
{
public:
CInner()
{
cout << "constructor of inner class CInner." << endl << endl;
}
};
public:
CA()
{
cout << "Constructor of CA." << endl;
cout << " m_i1 = " << m_i1
<< ", m_i2 = " << m_i2
<< ", m_i3 = " << m_i3
<< ", m_i4 = " << m_i4 << endl << endl;
}
{
public:
class CInner
{
public:
CInner()
{
cout << "constructor of inner class CInner." << endl << endl;
}
};
public:
CA()
{
cout << "Constructor of CA." << endl;
cout << " m_i1 = " << m_i1
<< ", m_i2 = " << m_i2
<< ", m_i3 = " << m_i3
<< ", m_i4 = " << m_i4 << endl << endl;
}
static void Func1()
{
cout << " In function Func1()." << endl;
static CInner myInner1;
}
{
cout << " In function Func1()." << endl;
static CInner myInner1;
}
static void Func2()
{
cout << " In function Func2(), m_i1 = " << m_i1 << endl;
if(m_i1 < 10)
{
cout << "m_i1 < 10 and Constructor of CInner won't be called!" << endl << endl;
return;
}
{
cout << " In function Func2(), m_i1 = " << m_i1 << endl;
if(m_i1 < 10)
{
cout << "m_i1 < 10 and Constructor of CInner won't be called!" << endl << endl;
return;
}
static CInner myInner2;
}
public:
static int m_i1;
static int m_i2;
static const int m_i3;
static int m_i4;
};
}
public:
static int m_i1;
static int m_i2;
static const int m_i3;
static int m_i4;
};
/* 不同模块的全局、static变量/对象初始化顺序不确定;
* 同一个编译模块按定义顺序初始化。
* 但有一点相同,就是它们均在编译期已分配好内存。
* 对于诸如基本数据类型,编译期能确定其值的,编译器就直接将值写入分配的空间,如“CA::m_i1=3"。
* 对于编译期不能确定值的,要等到运行时main函数之前初始化,如theCA、CA::m_i2。
* 但若static的初始化表达式均为const或字面常量等确定的值,则亦能在编译期确定值,如m_i4。
*/
int CA::m_i1 = 1;
CA theCA;
const int CA::m_i3 = 3;
int CA::m_i2 = CA::m_i1 + 1;
int CA::m_i4 = CA::m_i3 + 1;
* 同一个编译模块按定义顺序初始化。
* 但有一点相同,就是它们均在编译期已分配好内存。
* 对于诸如基本数据类型,编译期能确定其值的,编译器就直接将值写入分配的空间,如“CA::m_i1=3"。
* 对于编译期不能确定值的,要等到运行时main函数之前初始化,如theCA、CA::m_i2。
* 但若static的初始化表达式均为const或字面常量等确定的值,则亦能在编译期确定值,如m_i4。
*/
int CA::m_i1 = 1;
CA theCA;
const int CA::m_i3 = 3;
int CA::m_i2 = CA::m_i1 + 1;
int CA::m_i4 = CA::m_i3 + 1;
int main(int argc, _TCHAR* argv[])
{
CA::Func1();
CA::Func2();
{
CA::Func1();
CA::Func2();
cout << "After CA::m_i1 increased by 11 :" << endl;
CA::m_i1 += 11;
CA::Func2();
CA::m_i1 += 11;
CA::Func2();
return 0;
}
}
以上程序运行结果为:
Constructor of CA.
m_i1 = 1, m_i2 = 0, m_i3 = 3, m_i4 = 4
m_i1 = 1, m_i2 = 0, m_i3 = 3, m_i4 = 4
In function Func1().
constructor of inner class CInner
constructor of inner class CInner
In function Func2(), m_i1 = 1
m_i1 < 10 and Constructor of CInner won't be called!
m_i1 < 10 and Constructor of CInner won't be called!
After CA::m_i1 increased by 11 :
In function Func2(), m_i1 = 12
constructor of inner class CInner.
In function Func2(), m_i1 = 12
constructor of inner class CInner.