四种对象生存期和作用域 static用法总结

四种对象生存期和作用域

程序内存空间: 代码段,数据段,堆栈段
文本段。存储可执行文件的指令;也有可能包含一些只读的常数变量,例如字符串常量等。

栈对象

隐含调用构造函数

堆对象

隐含调用构造函数,要显式释放

全局对象

全局对象的构造先于main函数,对象在运行期间初始化,变量在编译器初始化

已初始化的全局变量存储于.data段中
未初始化的全局变量存储于.bss段中

静态对象(全局变量与局部变量)

已初始化的静态变量存储于.data段中
未初始化的静态变量存储于.bss段中

#include <iostream>
using namespace std;

class Test
{
public:
    Test(int n) : n_(n)
    {
        cout << "Test " << n_ << " ..." << endl;
    }
    ~Test()
    {
        cout << "~Test " << n_ << " ..." << endl;
    }
private:
    int n_;
};

int n;          //未初始化的全局变量,初始值为0。n存储于.bss段中
int n2 = 100;   //已初始化的全局变量,初始值为100。n2存储于.data段中。
Test g(100);    // 全局对象的构造先于main函数
static Test g2(200);

int main(void)
{
    cout << "Entering main ..." << endl;

    Test t(10);     // 栈上创建的对象,在生存期结束的时候自动释放
    {
        Test t(20);
    }

    {
        Test *t3 = new Test(30);        // 堆上创建的对象,要显式释放
        delete t3;
    }

    {
        static int n3;          // n3存储于.bss段中 (编译期初始化)
        static int n4 = 100;    // n4存储于.data段中(编译期初始化)

        static Test t4(333);    // t4对象运行期初始化   .data段
    }
    cout << "Exiting main ..." << endl;
}

运行结果

Test 100 ...
Test 200 ...
Entering main ...
Test 10 ...
Test 20 ...
~Test 20 ...
Test 30 ...
~Test 30 ...
Test 333 ...
Exiting main ...
~Test 10 ...
~Test 333 ...
~Test 200 ...
~Test 100 ...

static用法总结

  1. 用于函数内部修饰变量,即函数内的静态变量。
    这种变量的生存期长于该函数,使得函数具有一定的“状态”。使用静态变量的函数一般是不可重入的,也不是线程安全的

  2. 用在文件级别(函数体之外),修饰变量或函数,表示该变量或函数只在本文件可见,其他文件看不到也访问不到该变量或函数。全局变量,一般在.c文件中定义。若在.h文件定义会出现重复定义的情况。其他文件中使用全局变量,需要加extern申明

由于C++引入了类,在保持与C语言兼容的同时,static关键字又有了两种新用法:

  1. 用于修饰类的数据成员,即“静态成员”。这种数据成员的生存期大于class的对象。静态数据成员是每个class有一份,普通数据成员是每个instance 有一份。

  2. 用于修饰class的成员函数,即“静态成员函数”。这种成员函数只能访问静态成员和其他静态成员函数,不能访问非静态成员和非静态成员函数。