背景:
最近在写代码的时候,遇到一个bug,查了一天半才查出来,是由于对静态变量的错误使用所导致的(成员函数中的静态局部变量)。索性这里就把静态变量的使用一起看看。
先抛出我犯错误的问题:
对于成员函数中的静态局部变量, 在类的不同的实例中,访问该成员函数, 局部静态成员变量是不是共享的?
C基础的知识点就不多赘述了,这里默认大家是有一定的C基础。
静态变量, 就是用static修饰的变量,用来修饰变量的作用域和生命周期。
在C语言中,只有静态局部变量和静态全局变量。在C++中,又引入了静态成员变量, 成员函数中的静态局部变量。
也就是说,有以上4中不同类型的静态变量的使用,那么它们到底有什么区别,不要慌,一个一个来看,其实一点儿也不难。
先看下面一段代码,熟悉下前面提到的4种静态变量:
//test.cpp
static int global_s; //静态全局变量
void func()
{
static int local_s; //静态局部变量
}
class Test {
public:
void funcTest() {
static int t_local_s; //成员函数中的静态局部变量
}
private:
static int test_s; //静态成员变量
};
所有的静态变量,生命周期都是程序的开始到结束,也就是说和程序共存亡。区别在于它们的作用域不同。
都是在程序开始的时候分配内存。在C语句中初始化且只被初始化一次。
都是共享变量。
1.静态全局变量
定义在函数体外的静态变量,作用域在本文件,能被同文件中的所有函数访问,但不能被其它源文件的函数访问。
使用方法和全局变量类似, 只是多了作用域的限制。
2.静态局部变量
定义在普通函数体内的静态变量, 只能被该函数访问。在访问函数的时候进行一次初始化,之后再访问的时候不会再初始化,直接跳过初始化的语句,执行后面的操作。
3、静态成员变量
定义于class内部的静态变量,必须在类声明之后进行初始化后才能使用,然后通过类名来进行访问,如:
class Test {
private:
static int test_s;
};
int Test::test_s = 1; //初始化 静态成员变量
int main ()
{
printf("%d\n", Test::test_s);
return 0;
}
4、成员函数中的静态局部变量
其实它的作用域和生存周期和作用域和普通函数中的静态局部变量是一样的。
定义在成员函数体内的静态局部变量, 作用域在该成员函数内, 也只有在第一次访问的时候初始化一次,之后再访问的时候不会再初始化,直接跳过初始化的语句,执行后面的操作, 即使是不同的类实例,也是共用同一个。
class Test {
public:
void funcTest() {
static int test_local_s = 1;
printf("test_local_s = %d\n", test_local_s++);
}
}
int main()
{
Test t1, t2;
t1.funcTest();
t2.funcTest();
t1.funcTest();
t2.funcTest();
return 0;
}
运行结果:
test_local_s = 1
test_local_s = 2
test_local_s = 3
test_local_s = 4
有次可见,成员函数中的静态局部变量, 即使是相同的类,不同的实例, 也是共用同一个静态变量。
我之前遇到的bug就是以为不同的实例的成员函数中的静态局部变量不是公用的导致最后运行结果不对。
在此缅记:只要是静态的变量,那么它就只有一份,只能被初始化一次,且是被共享的!