在源代码被编译过程中,编译期会加入代码逻辑,以完成确定的内存分配 和 变量的初始化。分配内存,并非实际分配内存,而是写入其内存分配大小信息
如:全局变量为内置类型,并且大小确定
int a=2; static int b=3; //static的不同只是其只在本文件中可见 static int c=a+b;
1.1 全局变量在编译期初始化,那么在实际运行期都是确定的结构和逻辑,将带来更高的性能,因为编译器完成了一定的工作。
1.1.1 编译时初始化(静态初始化)全局变量在main函数第一次使用它之前,就把它初始化好。但这个初始化可细分为:
编译时初始化 和 加载时初始化,即static initialization 和 dynamic initialization。(静态变量见 5 补充)
2 加载时初始化是针对于那些简单的、c++内部定义的数据结构(也称 内置结构),如int,double,bool 及 数组结构 的初始化,又可分为两种方式:
- .bss段 未初始化的变量,也就是我们没指定初值,编译器分配0值给它,编译时编译器将其分配在.bss段,不占用rom空间
- .data 段 已初始化的变量,也就是我们指定了初值,编译器将其分配在.data段,占用rom空间。
全局类对象在main函数执行前,由加载程序完成其初始化,其无法在编译期初始化,由于那时候还无法调用类的构造函数。
同时,在加载期,是线程安全的。例如,饿汉方式的单例类:
借助main执行前的加载期完成初始化,由于还在加载所以确保线程安全。
class A
{
private:
A(){}
static A* instance;
public:
static A* getInstance()
{
return instance;
}
};
A* A::instance=new A(); //main 执行前的加载期,完成的初始化
int main()
{
}
3 运行期初始化
指代实际程序运行期间对象(变量)的创建,包含那些动态创建的对象。由于编译和加载时无法确定大小,因此它们只能延迟到运行期才能完成初始化,将带来程序的性能开销。并且由于运行期间可能是多线程环境,对于共享变量,还可能带来线程安全问题。
int main()
{
int* p=new int[N];
A* arr=new A(0);
}
另外针对静态变量,若其是普通的具有本文可见性的普通静态变量
其可能在编译期(内置类型)初始化或者在加载期(类的静态成员)初始化。
但针对函数内部的局部static变量,其在第一次被调用时初始化,并且只初始化一次。
4 总结类的静态成员
c++规定,const的静态成员可以直接在类内进行初始化,而非const的静态成员需要在类外声明以初始化,对于后一种情况,我们一般选择在类的实现文件中初始化。至此,具体的初始化方式和上面说的是一致的,可在编译期间初始化,也可在运行期间初始化。
在类中定义const变量有以下两个好处:
1.静态数据成员没有进入程序的全局名字空间,因此不存在与程序中的其他全局名字冲突的可能性。
2.可以实现信息的隐藏。
#includeusing namespace std; class sb{ private: const int i=5; public: void print(); };
5 补充另外,静态初始化先于动态初始化。因为静态初始化发生在编译时期,直接写进.bss段和.data段,在程序执行时直接加载;而动态初始化则是在运行时期,由运行时库调用相应构造函数进行初始化,同样要写进.bss段或.data段。
.data段和.bss段的区别:
.data段存放的是已初始化好的全局变量和静态变量;
.bss段存放的是未初始化的全局变量和静态变量,给其赋0值【在有些编译器中,初始化为0的静态变量和全局变量也放在.bss段】



