zoukankan      html  css  js  c++  java
  • 四种不同对象的生存方式(栈、堆、全局、局部静态)

       [结果分析,引申出四种对象]:

     

    生存方式

    执行时机

    消亡时机

    全局(静态)对象

    全局静态存储区global

    比程序进入点更早,构造函数先被执行;

    程序结束前,其析构函数被执行。

    局部静态对象

    局部静态存储区local static

    在对象诞生时,其构造函数被执行。(注意,此处只会有一个实例产生,而且固定在内存上(非stack也非heap),它的构造函数在控制权第一次移转到其声明处时被调用。

    程序将结束时(此对象因而将遭致毁灭)其析构函数才被执行,但比全局对象的析构函数更早一步执行。

    局部对象

    栈区 stack

    在对象诞生时,其构造函数被执行。(同局部静态对象)

    程序流程将离开该对象的存活范围时(以至于该对象将销毁)时,其析构函数被执行。

    new方式产生的局部对象

    堆区 heap

    当对象诞生时,其构造函数被执行。(同局部静态对象、局部对象)

    在对象被delete时执行析构函数。(注意,不加delete该heap区空间不会自动释放的,如果程序长期运行,会“吃掉”很多内存,造成结果不可预知。)

     

    [静态对象的深入探究(全局、局部)]

     

    从产生抑制持续到程序结束的那些对象,在这个过程中不会动态的消亡,所以叫静态对象

     

    全局静态对象

    局部静态对象

    1.初始化时机

    1)在main函数的代码前进行初始化;

    2)类中静态、全局对象的初始化时机与该类的对象并无关系(强调:出现在类定义中的静态变量语句只是声明,对于要使用的类的静态成员变量,必须还要在类外进行定义,否则使用时会发生链接错误。声明并不会导致空间的分配,只有定义才会使其被生成。也就是如果你对类的静态成员进行了定义,那么它就肯定会被分配空间并初始化。就像全局变量一样);

    初始化发生在函数被调用期间,首次碰到该定义时。

    2.举例(区分全局、局部静态对象)

    1)定义于namespace的对象;

    2)在class, file里的static对象;

    3)类中的静态变量和全局变量;

    定义在函数里的为局部静态对象

    3.如何实现的?

    对于non-local静态变量的初始化,编译器实际上是这样实现的。对每个编译文件里需要初始化的静态变量,生成一系列的sti_开头的函数,在里面完成初始化调用语句,然后把这些sti_函数抽取出来,形成一个初始化函数表,然后在__main()函数里调用,然后把这个函数放到main里的开头。

    而对于local静态变量,为了实现第一次碰到时初始化,附加了一个全局变量,标志该对象是否被初始化,同时在析构时检查这个变量。这样就保证了第一次碰到时初始化,同时只有在执行了构造函数的时候,才会在程序退出时执行对应的析构函数。

    全局变量与全局静态变量的区别

    (a)若程序由一个源文件构成时,全局变量与全局静态变量没有区别。

    (b)若程序由多个源文件构成时,全局变量与全局静态变量不同:全局静态变量使得该变量成为定义该变量的源文件所独享,即:全局静态变量对组成该程序的其它源文件是无效的。

    静态全局变量的作用:

    (a)不必担心其它源文件使用相同变量名,彼此相互独立。

    (b)在某源文件中定义的静态全局变量不能被其他源文件使用或修改。

    例如:一个程序由两个源文件组成,其中在一个源文件中定义了“int n;”,在另一个源文件中定义了“static int n;”则程序给它们分别分配了不同的空间,两个值互不干扰。

    例如:下面在file1.cpp中声明全局变量n,在file2.cpp中定义全局静态变量n。文件file1.cpp和file2.cpp单独编译都能通过,但连接时,file1.cpp中的变量n找不到定义,产生连接错误。

    // file1.cpp
    # include
    void fn()
    extern int n;
    void main()
    {
        n=20;
        cout<<n<<endl; p="" <="">
        fn();
    }
    // file2.cpp
    # include
    static int n; // 默认初始化为0,注意此处定义的n 只能在file2.cpp中使用。
    void fn()
    {
        n++;
        cout<<n<<endl; p="" <="">
    }

    静态函数:使某个函数只在一个源文件中有效,不能被其他源文件所用。

    定义:在函数前面加上static。

    说明:函数的声明和定义默认情况下在整个程序中是extern的。

    静态函数的效果:

    (1)它允其他源文件建立并使用同名的函数,而不相互冲突。

    (2) 声明为静态的函数不能被其他源文件所调用,因为它的名字不能得到。    

    拙见:

    静态变量和函数一般都局限于一个编译单元也就是.cpp文件中。

    静态变量和私有变量的最主要的区别就在于:他们分配内存空间的方式不一样。静态变量的内存是在程序开始执时变量就占用了内存,直到程序结束时变量才释放内存.私有变量(或者说是局部变量,不知道你是不是指这个:)),是在程序运行到该步的时候分配内存。所以,当离开了该私有变量的作用域的时候,私有变量的内存空间会被释放。所以:静态变量只的值只会初始化一次,后面每次访问,都是上次处理过的值,(即使是在一个函数内部)。私有变量每次都初始化。看下面的实践:

    class Program
    {
        static void Main(string[] args)
        {//输出未经定义的静态变量,结果为0;也说明了,在C#中未赋初值的变量系统自动赋为0
        Console.WriteLine(sort.i);          
        //静态变量的访问方法(类名.静态变量名),而且还可以在外部操作静态变量呢,可见静态变量并不神秘;
        sort.i = 5;
        //输出5
        Console.WriteLine(sort.i);
        //还可以通过构造函数对静态变量初值呢,呵        
        sort sortTest = new sort();
        //输出构造函数中的赋值 3;
        Console.WriteLine(sort.i);
        }
    }
    class sort
    {
        public static int i;
        public sort()
        {
            i = 3;
        }      
    }

    总结:在类内部访问静态变量时,直接用静态变量名即可,不用以(类名.静态变量名),这样的方式访问,除了有静态变量之外,还有静态类实例,还有静态方法.但用法都是大同小异;(没有静态类哦,呵呵越论越傻了),如:

    public static void myFun(){}   //静态方法

    private static Random MyRandom=new Random(); //静态类实例

    之所以有时声明为私有静态变量,是为了让它只初始化一次.这样节省了内存空间但又想让它在外部是不可访问的,这样利用私有这个访问限定符就搞定了. 私有静态:安全又节省空间.

    例:如果想在每次实例化类的时间生成一组随机数,但产生随机数是要用到一个类的,即Random,这个类不是静态类,它要产生实例,用产生的实例来生成随机数,但如果在每次类实例化时都产生一个Random实例,那内存空间简直是极大的浪费,所以可以用:

    private static Random MyRandom=new Random();

    这样每次类实例化时,都会用同一个Random实例MyRandom来产生随机数

    参见:

    存储持续性、作用域和链接性

    C++类中的static数据成员,static成员函数 

  • 相关阅读:
    Docker最全教程之MySQL容器化 (二十四)
    Docker最全教程之使用Node.js搭建团队技术文档站(二十三)
    Docker最全教程之使用PHP搭建个人博客站点(二十二)
    构建自己的简单微服务架构(开源)
    使用Jmeter进行http接口测试
    Appium 服务关键字
    Appium入门示例(Java)
    Appium for win7 环境搭建
    android adb常用指令
    Android测试环境搭建(win7)
  • 原文地址:https://www.cnblogs.com/yyxt/p/4912271.html
Copyright © 2011-2022 走看看