(转-经典-数据段)C++回顾之static用法总结、对象的存储,作用域与生存期
转自:https://blog.csdn.net/ab198604/article/details/19158697
相关知识补充:https://www.cnblogs.com/rednodel/p/9300729.html
在C语言中,static的用法非常简单,只有两种:
(1)用于函数内部修饰变量,即函数内的静态变量。这种变量的生存期大于函数,使得函数具有一定的“状态”,使用静态变量的函数一般是不可重入的,也不是线程安全的。如strtok(3).
(2) 用在文件级别,函数体外, 修饰变量或函数,表示该变量或函数只在本文件内可见。其它文件看不到也访问不到该变量或函数。
在C++中,保留了C的上面用法,除此以外,还有以下两种新用法:
(1) 用于修饰类的数据成员,即所谓的“静态成员”, 这种数据成员的生存期大于类对象(实例),静态数据成员是每个class有一份, 普通数据成员是每个类对象(实例)有一份。
(2) 用于修饰类的成员函数,即所谓的“静态成员函数”,这种成员函数也只能访问静态成员和其它静态成员函数,不能访问非静态成员与非静态成员函数。
关于对象的作用域与生存期
需要明确一点的是,作用域与生存期在某些情况下是不一致的,它们并不等同。下面是存储器模型:
程序在存储器中按上述模型存放,它有代码段,数据段,堆和栈之分。代码段是只读的,数据段分为未初始化的数据段.bss(block started by symbol)和已初始化的数据段.data段。未初始化数据段.bss的特征是在可执行文件中不占空间,在运行时才分配空间,而.data段在编译期间就被初始化,在可执行文件中占据空间。
对于全局变量
如int a; 未被初始化,所以它存放在.bss段中
如int a = 100; 已初始化,故它存放在.data段中.
对于静态全局变量
如static int a; 未被初始化,它存放在.bss段中
如static int a = 100; 已初始化,故它存放在.data段中
对于静态局部变量
如下所示:
- int main()
- {
- ...
- {
- //下面a,b的作用域在{}内,生存期在整个程序的生存期之内
- static int a; //存储于.bss段中
- static int b = 100; //存储于data段中。
- }
- }
对于全局对象与静态全局对象
如Test g(10); static Test g(10); 它们存放在data段中,但运行时,对象的构造函数都是先于main函数调用的,在main函数结束后自动调用析构函数销毁
对于局部对象
- int main()
- {
- ....
- Test t(10);//局部对象在栈上创建,生存期在main块作用域范围之内,main结束后自动调用析构函数销毁
- }
如果在以下情况,它将在{}作用域结束后就自动调用析构函数销毁
- int main()
- {
- ...
- {
- Test t(10); //在栈上创建,作用域在{}
- }//退出{}后就自动销毁对象
- }
对于静态局部对象
如下:
- int main()
- {
- ...
- {
- //均存储在data段中,作用域在{}之内,生存期在整个main结束后才自动调用析构函数销毁。
- static Test t(100);
- static Test t2;
- }
- }
对于堆上的对象
如下:
- int main()
- {
- ...
- {
- Test *t3 = new Test(20); //堆上创建的对象,即使跳出作用域{}也不能自动调用析构函数来释放对象。可见作用域与生存期是不同的。作用域仅仅是对象的可见范围。
- delete *t3; //主动析构。
- }
- }
总而言之,静态全局对象,全局对象,静态局部对象都存储在data段中,静态全局对象与全局对象先于main函数调用构造函数,但它们三个都在main结束后自动调用析构函数销毁对象。堆上对象创建于堆,离开作用域范围后依旧不会自动销毁,需要手动销毁对象。局部对象创建于栈上,离开作用域后自动销毁。只有全局的普通变量才区分.bss段与.data段,未被初始化的全局变量存放在.bss段中,初始化的全局变量存放在data段中,全局变量作用域在整个程序的生命周期。局部变量在栈上创建,作用域在局部。另外切记,作用域与生存期有时并不等同。