四种不同对象的生存方式(栈、堆、全局、局部静态)

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

 

生存方式

执行时机

消亡时机

全局(静态)对象

全局静态存储区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成员函数 

posted @ 2015-10-26 20:17  小天_y  阅读(2512)  评论(0编辑  收藏  举报