荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Peter (小飞侠), 信区: Program
标  题: Visual C++ 中的对象生存期
发信站: BBS 荔园晨风站 (Wed Jan 27 17:47:49 1999), 转信


  Visual C++中对象何时创建及何时取消,即对象的生存期,是程序员
比较关心的问题,处理不好会造成内存浪费,影响应用的运行。本文通
过一个例子来探讨一下这个问题。
    对象的生存期
    从对象被创建到对象被取消这一期间我们称之为对象的生存期。
要弄清对象的生存期实质上就是要弄清对象何时被创建、何时被取消
这两个问题。对象的创建是较为直观的,但对象何时被取消(释放其所
占的内存区)似乎比较抽象一点。究竟什么时刻、按何种顺序创建/
取消对象(若在某一程序控制范围内包含多个对象)对某些C++ 程序员
来讲可能并不十分清楚。我们知道:任何一个对象在创建/取消时都会
调用其相应的构造 /析构函数。 如果我们让构造函数(析构函数)除
了做初始化类的变量及分配内存(释放内存及处理)还做点比如打印信
息之类的"显示"工作, 我们就可以通过显示的信息获知某对象是何时
被创建及何时被取消的。
    创建对象一般有两种方式:
    1.在栈中定义对象,其一般格式如下:
     类名 对象名 (参数表);
    栈中对象的特点:当程序执行超出栈中类对象的作用域时(即在该
对象的生存期终止时) ,它们会自动被调用其相应的析构函数来释放
其对应对象所占的内存区及处理其它善后事务。

    2.在堆中申请对象(在自由存储区中分配对象),其一般格式如下:
    类名* 类指针名 = new 类名 (参数表);
    堆中对象的特点:一旦对象在堆中创建,程序执行过程中除非使用
delete等操作符来取消该对象,否则该对象将一直生存下去。操作符d
elete使用格式如下:
    delete 类指针名;
    执行该语句的作用是释放该指针所指对象所占的自由存储区。若
此对象的类有一个已定义的析构函数,delete操作符会调用它来做析
构函数所要做的事情:释放对应对象所占自由存储区、处理善后事务;
否则delete操作符会调用编译器为该函数自动生成的析构函数来释放
自由存储区。
    程序举例
    #include "iostream.h"
    #include "conio.h"
    class k{
      public:
      k()
      {
        cout << "enter k class " << endl;
      }
      ~k()
      {
        cout << "out of k class " << endl;
      }
    };//class k
    class kkk{
      public:
      kkk()
      {
        cout << "enter kkk class " << endl;
      }
      ~kkk()
      {
        cout << "out of kkk class " << endl;
      }
    };//class kkk
    class kk{
      public:
      kk()
      {
        cout << "enter kk class " << endl;
        kkk third;
      }
      ~kk()
      {
        cout << "out of kk class " << endl;
      }
      k first;
    };//class kk
    class xq:public kk,virtual public k,protected kkk{
    public:
    xq()
    {
      cout << "enter class xq" <<endl;
    }
    k first;
    ~xq()
    {
      cout << "come out class xq " << endl;
      cout << endl;
    }
    kk second;
    }; // class xq
    k* point = new k;
    kkk third;
    void main(void)
    {
      cout << "enter the main functoin !" << endl;
      xq ttt;
      getch();
    }
    程序执行结果如下:
    enter k class
    enter kkk class
    enter the main functoin !
    enter k class
    enter k class
    enter kk class
    enter kkk class
    out of kkk class
    enter kkk class
    enter k class
    enter k class
    enter kk class
    enter kkk class
    out of kkk class
    enter class xq
    come out class xq
    out of kk class
    out of k class
    out of k class
    out of kkk class
    out of kk class
    out of k class
    out of k class
    out of kkk class
    通过以上例子,我们总结如下规则:

    1.对于在堆中用new  等操作符申请的对象,进程不会自动释放其
所占的自由存储区,只能通过程序员使用delete等操作符来释放该对
象所占自由存储区。其创建的顺序为:谁先被申请,谁先被创建;其取
消的顺序为:谁先使用操作符取消,则谁先被取消。换句话说:在堆中
申请对象其创建与取消顺序只与程序员的操作顺序有关。如 果某个
对象在其对应的作用域范围内未被取消(指在堆中创建的对象),且我
们又没有做适当的处理,那么进程在离开该对象作用域范围后将无法
对其进行访问,但其所占的自由存储区并未被取消,这样就会造成对内
存的浪费。故建议大家在不使用这些对象时,一定不要忘记用delete
等操作符来取消它们。
    2.对于在栈中定义的对象,当程序执行超出该对象的作用域时会
被自动取消。对于处于同一程序控制范围的对象,其创建顺序为:谁先
定义则谁先被创建;其取消顺序与创建顺序刚好相反(栈式管理的特点
)。我们可以用"{"与"}"来限制这类对象的生存期。由此可见,对于在
堆中申请的对象,其创建与取消比较死板而栈中对象则灵活些,故以下
如不作特殊说明,谈及的对象均指在栈中定义的对象。

    3.如果类中的数据成员包含对象(内嵌对象或类嵌套)或类所属的
构造函数包含对象,那么其创建顺序为:先创建构造函数外的对象(不
管其属于私有、公有或保护对象,一律按其在类中出现的顺序由先到
后创建),然后创建该类对象,最后创建构造函数中的对象(其创建顺序
遵从规则2中原则)。其取消顺序为:对于在构造函数中创建的对象,当
构造函数调用结束时, 进程将会按与创建时相反的顺序来取消它们;
对于在构造函数外的对象, 当程序执行超出该类对象作用域范围时,
进程将以与创建时相反的顺序来取消它们。当要创建含有多层类嵌套
的对象时,进程将会从最里层向最外层进行创建,而在取消时则与创建
相反。如果类中的成员函数中定义(申请)了对象,当且仅当该成员函
数被调用时,这些在成员函数中的对象才会被创建,当进程离开此函数
时会自动取消这些对象(对于在堆中申请的对象只能由程序员自已来
取消)。如果类中的析构函数中定义(申请)了对象,则只有该析构函数
被调用时它们才被创建, 当进程离开该析构函数时进程会自动取消它
们。

    4.对于派生类对象的创建有这样的规则:先创建它的基类,后创建
自身。 创建基类的顺序为:按说明的先后顺序创建(当基类中含有虚
基类时,虚基类先于非虚类创建)。 当然,倘若该派生类内嵌对象,在
创建自身时,应遵循规则3)。
    5.对于全程对象,其构造函数在调用main 函数之前被调用,其析
构函数在main函数调用完成之后作为退出过程的 一部分而被调用(对
于在堆中申请的全程对象的取消必须由程序员来完成)。

--
※ 来源:.BBS 荔园晨风站 bbs.szu.edu.cn.[FROM: 192.168.1.3]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店