C++析构函数及生存期

本文总结自http://c.biancheng.net/view/164.html

析构函数(destructor)是成员函数的一种,它的名字与类名相同,但前面要加~,没有参数和返回值。

一个类有且仅有一个析构函数。如果定义类时没写析构函数,则编译器生成默认析构函数。如果定义了析构函数,则编译器不生成默认析构函数。

析构函数在对象消亡时即自动被调用。 可以定义析构函数在对象消亡前做善后工作。例如,对象如果在生存期间用 new 运算符动态分配了内存,则在各处写 delete 语句以确保程序的每条执行路径都能释放这片内存是比较麻烦的事情。有了析构函数,只要在析构函数中调用 delete 语句,就能确保对象运行中用 new 运算符分配的空间在对象消亡时被释放。例如下面的程序:

class String{
private:
    char* p;
public:
    String(int n);
    ~String();
};
String::~String(){
    delete[] p;
}
String::String(int n){
    p = new char[n];
}

String 类的成员变量 p 指向动态分配的一片存储空间,用于存放字符串。动态内存分配在构造函数中进行,而空间的释放在析构函数 ~String() 中进行。这样,在其他地方就不用考虑释放空间的事情了。

只要对象消亡,就会引发析构函数的调用。下面的程序说明了析构函数起作用的一些情况。

#include<iostream>
using namespace std;
class CDemo {
public:
    ~CDemo() {  //析构函数
        cout << "Destructor called"<<endl;
    }
};
int main() {
    CDemo array[2];  //构造函数调用2次
    CDemo* pTest = new CDemo;  //构造函数调用
    delete pTest;  //析构函数调用
    cout << "-----------------------" << endl;
    pTest = new CDemo[2];  //构造函数调用2次
    delete[] pTest;  //析构函数调用2次
    cout << "Main ends." << endl;
    return 0;
}

程序的输出结果是:

Destructor called
-----------------------
Destructor called
Destructor called
Main ends.
Destructor called
Destructor called

第一次析构函数调用发生在第 13 行,delete 语句使得第 12 行动态分配的 CDemo 对象消亡。

接下来的两次析构函数调用发生在第 16 行,delete 语句释放了第 15 行动态分配的数组,那个数组中有两个 CDemo 对象消亡。最后两次析构函数调用发生在 main 函数结束时,因第 11 行的局部数组变量 array 中的两个元素消亡而引发。

函数的参数对象以及作为函数返回值的对象,在消亡时也会引发析构函数调用。例如:

#include <iostream>
using namespace std;
class CDemo {
public:
    ~CDemo() { cout << "destructor" << endl; }
};
void Func(CDemo obj) {
    cout << "func" << endl;
}
CDemo d1;
CDemo Test() {
    cout << "test" << endl;
    return d1;
}
int main() {
    CDemo d2;
    Func(d2);
    Test();
    cout << "after test" << endl;
    return 0;
}

程序的输出结果是:

func
destructor
test
destructor
after test
destructor
destructor

程序共输出 destructor 四次:
第一次是由于 Func 函数结束时,参数对象 obj 消亡导致的。
第二次是因为:第 20 行调用 Test 函数,Test 函数的返回值是一个临时对象,该临时对象在函数调用所在的语句结束时就消亡了,因此引发析构函数调用。
第三次是 main 函数结束时 d2 消亡导致的。
第四次是整个程序结束时全局对象 d1 消亡导致的。

构造函数、析构函数和变量的生存期

构造函数在对象生成时会被调用,析构函数在对象消亡时会被调用。对象何时生成和消亡是由对象的生存期决定的。下面通过一个例子来加深对构造函数、析构函数和变量的生存期的理解。

#include <iostream >
using namespace std;
class Demo {
    int id;
public:
    Demo(int i)
    {
        id = i;
        cout << "id=" << id << "constructed" << endl;
    }
    ~Demo()
    {
        cout << "id=" << id << "destructed" << endl;
    }
};
Demo d1(1);
void Func()
{
    static Demo d2(2);
    Demo d3(3);
    cout << "func" << endl;
}
int main()
{
    Demo d4(4);
    d4 = 6;
    cout << "main" << endl;
    {
        Demo d5(5);
    }
    Func();
    cout << "main ends" << endl;
    return 0;
}

运行结果(行号只是为了便于查看,它不是输出的一部分):

01) id=1constructed
02) id=4constructed
03) id=6constructed
04) id=6destructed
05) main
06) id=5constructed
07) id=5destructed
08) id=2constructed
09) id=3constructed
10) func
11) id=3destructed
12) main ends
13) id=6destructed
14) id=2destructed
15) id=1destructed

要分析程序的输出,首先要看有没有全局对象。因为全局对象是进入 main 函数以前就形成的,所以全局对象在 main 函数开始执行前就会被初始化。

本程序第 16 行定义了全局对象 d1,因此 d1 初始化引发的构造函数调用,导致了第 1) 行的输出结果。

main 函数开始执行后,局部对象 d4 初始化,导致第 2) 行输出。

第 26 行,d4=6;,6 先被自动转换成一个临时对象。这个临时对象的初始化导致第 3) 行输出。临时对象的值被赋给 d4 后,这条语句执行完毕,临时对象消亡,因此引发析构函数调用,导致第 4) 行输出。

第 29 行的 d5 初始化导致第 6) 行输出。d5 的作用域和生存期都只到离它最近的,且将其包含在内的那一对{}中的}为止,即第 30 行的},因此程序执行到第 30 行时 d5 消亡,引发析构函数调用,输出第 7) 行。

第 8) 行的输出是由于进入 Func 函数后,执行第 19 行的静态局部对象 d2 初始化导致的。

静态局部对象在函数第一次被调用并执行到定义它的语句时初始化,生存期一直持续到整个程序结束,所以即便 Func 函数调用结束,d2 也不会消亡。

Func 函数中的 d3 初始化导致了第 9) 行输出。

第 31 行,Func 函数调用结朿后,d3 消亡导致第 11) 行输出。

main 函数结束时,其局部变量 d4 消亡,导致第 13) 行输出。

整个程序结束时,全局对象 d1 和静态局部对象 d2 消亡,导致最后两行输出。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
系统根据B/S,即所谓的电脑浏览器/网络服务器方式,运用Java技术性,挑选MySQL作为后台系统。系统主要包含对客服聊天管理、字典表管理、公告信息管理、金融工具管理、金融工具收藏管理、金融工具银行卡管理、借款管理、理财产品管理、理财产品收藏管理、理财产品银行卡管理、理财银行卡信息管理、银行卡管理、存款管理、银行卡记录管理、取款管理、转账管理、用户管理、员工管理等功能模块。 文中重点介绍了银行管理的专业技术发展背景和发展状况,随后遵照软件传统式研发流程,最先挑选适用思维和语言软件开发平台,依据需求分报告模块和设计数据库结,再根据系统功能模块的设计制作系统功能模块图、流程表和E-R图。随后设计架以及编写代码,并实现系统能模块。最终基本完成系统检测和功能测试。结果显示,该系统能够实现所需要的作用,工作状态没有明显缺陷。 系统登录功能是程序必不可少的功能,在登录页面必填的数据有两项,一项就是账号,另一项数据就是密码,当管理员正确填写并提交这二者数据之后,管理员就可以进入系统后台功能操作区。进入银行卡列表,管理员可以进行查看列表、模糊搜索以及相关维护等操作。用户进入系统可以查看公告和模糊搜索公告信息、也可以进行公告维护操作。理财产品管理页面,管理员可以进行查看列表、模糊搜索以及相关维护等操作。产品类型管理页面,此页面提供给管理员的功能有:新增产品类型,修改产品类型,删除产品类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值