C++中static变量的初始化

作者:billy
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

前言

在C语言中,static变量如果初始化,那么初始化发生在任何代码执行之前,属于编译期初始化。全局变量、static全局变量、static局部变量,此三者的生命周期、初始化方法完全一致,只是可见范围不同。

而在C++中我们引入了对象,这给全局变量的管理带领新的麻烦。C++的对象必须由构造函数生成,并最终执行析构操作。由于构造和析构并非分配内存那么简单,可以说相当复杂,因此何时执行全局或静态对象的构造和析构呢?这需要执行相关代码,无法在编译期完成。因此不同的static变量,在不同的时间被初始化,我们需要分情况来讨论。

编译时初始化

如果静态变量本身是基本数据类型(POD),且初始化值是常量,那么这个初始化过程是在编译期间完成的。

static int val = 10;
static char strArray[] = "hello world !";

加载时初始化

程序被加载时立即进行的初始化。这个初始化发生在main函数之前。即使程序任何地方都没访问过该变量, 仍然会进行初始化,因此形象地称之为"饿汉式初始化"。

  1. 静态变量是一个基本数据类型,但是初始值非常量
static int *p = new int[1024];

int x = 3;
int y = 4;
static int z = x + y;
  1. 静态变量是一个类对象,这种情况下即使是使用常量初始化,也是加载时初始化,而不是编译时初始化
static std::string str = "Hello world !";

class MyClass {
public:	
	MyClass();    
	MyClass(int a, int b)
;};

static MyClass* MyClass1 = new MyClass();
static MyClass MyClass2;

运行时初始化

这个初始化发生在变量第一次被引用
也就是说,从程序执行模型角度看,程序所在进程空间中,哪个线程先访问了这个变量,就是哪个线程来初始化这个变量。因此,相对于加载初始化来说,这种初始化是把真正的初始化动作推迟到第一次被访问时,因而形象地称为"懒汉式初始化"。

int myfunc()
{     	
    static std::string msg = "hello world !";    //运行时初始化
}

static 初始化的原理

例1:
int main()
{
    for(int x = 5; x < 10; x++)
    {
        static int y = x;	//第一次被引用时初始化,并且只初始化一次
        cout << "x = " << x << ", y = " << y << endl;
    }
    return 0;
}

输出结果:
x = 5, y = 5
x = 6, y = 5
x = 7, y = 5
x = 8, y = 5
x = 9, y = 5
例2:
int main()
{
    for(int x = 5; x < 10; x++)
    {
        static int y = x;
        cout << "x = " << x << ", y = " << y << endl;

        int *p = &y;
        p++;
        *p = 0;
    }
    return 0;
}

输出结果:
x = 5, y = 5
x = 6, y = 6
x = 7, y = 7
x = 8, y = 8
x = 9, y = 9

通过两个例子的结果我们可以知道,静态变量的初始化就是通过静态变量后面的一个32位内存位来做记录,以标识这个静态变量是否已经初始化。每次运行到当前位置,会先去判断这个地址:
如果不是1,就给它赋值1,然后给变量赋值;
如果是1,直接跳过赋值代码块这样它就做到了只赋值一次的效果;

在例2中我们每次都将这个值赋值为0,所以程序就一直认为变量一直没有被初始化过,并每次都初始化。该操作并非一个原子操作,因此从代码逻辑角度来说,static变量并不具有“线程安全”性能。

总结

  1. 如果是编译时和加载时初始化,是不会存在线程安全这个问题的。因为这两种初始化一定发生在Main函数执行之前,这个时候尚未进入程序运行空间,而这些初始化一定是在单线程环境下操作的。
  2. 如果是运行时初始化,因为无法保证访问这个静态变量一定只会从某个特定的线程中被访问,因此会存在"线程安全"的问题。
发布了61 篇原创文章 · 获赞 218 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_34139994/article/details/105157313