c++析构函数
首先我们来看一下有关析构函数的文字描述
1、定义
析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。
2、 作用:对象消亡时,自动被调用,用来释放对象占用的空间
3、特点:
(1) 名字与类名相同
(2) 在前面需要加上"~"
(3) 无参数,无返回值
(4) 一个类最多只有一个析构函数
(5) 不显示定义析构函数会调用缺省析构函数
#include<iostream>
using namespace std;
class Test
{
int id;
public:
Test()
{
}
Test(int i)
{
id = i;
}
~Test()
{
cout<<"ID: "<<id<<" destruction function is invoked!"<<endl;
};
};
int main()
{
Test t0(0); //栈中分配
Test t1[3]={1,1,1}; //栈中分配
Test *t2 = new Test(2); //堆中分配
delete t2;
Test *t3 = new Test[3]{3,3,3}; //堆中分配
delete []t3;
cout<<"------End of Main-------"<<endl;
return 0;
}
在给出运行结果以前有必要说一下,我在vs2012的编译器里也运行了这段代码。但是其中Test *t3 = new Test[3]{3,3,3};
这行代码是有错误的,我去查阅了相关的博客资料发现,在C++11中引进了这一新功能,即用new申请动态数组时可以直接初始化,形式如下:
int* p = new int[cnt](); //其中cnt长度和int类型都可以自己定义。
int* p = new int[cnt]{ };
而且可以用这个方式给每个成员赋值。
int* a = new int[10] { 1,2,3,4,5,6,7,8,9,10 };
所以说上面的Test *t3 = new Test[3]{3,3,3};
语句就应该是没问题的,下面给出运行结果。
解释:
在main函数中创建了t0,t1,t2,t3几个对象,这里先说一下C++创建对象的三种不同方式:
1、Test t0(0); //栈中分配内存
2、Test t1[3]={1,1,1}; //栈中分配内存
3、Test *t2 = new Test(2); //堆中分配内存
4、Test *t3 = new Test[3]{3,3,3}; //堆中分配内存
方法1、2中都是在栈中分配内存,在栈中内存由系统自动的去分配和释放,而使用new创建的指针对象是在堆中分配内存,当不需要该对象时,需要我们手动的去释放(delete),否则会造成内存泄漏。
在上述程序中,t0和t1都是栈中的对象,在程序结束时由系统来释放,因此出现在-----End of Main----之后。t2,t3是new出来的堆中对象,所以需要手动的delete释放,因此出现在最前面。另外有一点发现,就是栈中对象的释放顺序,是后定义的先释放,经过几次验证也如此,我想这恰好应征了栈的后进先出的特征。(先释放1,后释放0)
class Test
{
int id;
public:
Test(int i)
{
id = i;
}
~Test()
{
cout<<"ID: "<<id<<" destruction function is invoked!"<<endl;
};
};
Test t0(0); //最先创建的对象,最后释放
void Func()
{
static Test t1(1);
//创建静态对象,会在整个程序结束时自动释放
Test t2(2); //在Func结束时自动释放
cout<<"-----Func-----"<<endl;
}
int main()
{
Test t3(3);
t3 = 10;
//类型转换构造函数,这里会创建临时对象,将int型转成Test类型对象,
//在赋值结束后,临时变量销毁
cout<<"------Begin of Main-------"<<endl;
{
Test t4(4);
//花括号代表作用域,不需要等到main方法结束就释放了
}
Func(); //进入Func函数
cout<<"------End of Main-------"<<endl;
return 0;
}
那让我们先分析一波 先是t3,t3创建完成以后想要把10赋值过来,但是一个是int类型,一个是Test,这里就会创建临时对象,将int型转成Test类型对象,在赋值结束后,临时变量销毁(把临时创建的对象得10赋值给了t3),销毁临时对象,调用一次析构函数,然后是------Begin of Main-------,到了t4,因为是在花括号里,直接调用了一次析构函数,不需要等到main方法结束,(此处如果没有花括号那么它应该在哪里呢,答案当然是在t3前面 也就是------End of Main-------之后的10前面),到了Func(); 里面的t1和t2,t1静态对象,会在整个程序结束时自动释放,t2在Func()结束时释放,所以先------Func------在调用析构函数,然后------End of Main-------,接着是释放t3,静态t1,最前面最先定义的t0;